Я пытаюсь получить активный редактор С# IWpfTextView в расширении VS2019. Я использую небольшую службу MEF для внедрения представления в VSAsyncPackage. Но это не очень надежно — иногда введенный вид неверен (например, из другого вида) или отсутствует. Вот услуга:
public interface IActiveViewAccessor
{
IWpfTextView? ActiveView { get; }
}
[Export(typeof(IWpfTextViewConnectionListener))]
[Export(typeof(IActiveViewAccessor))]
[ContentType("text")]
[TextViewRole(PredefinedTextViewRoles.Document)]
internal sealed class ActiveViewConnectionListener : IWpfTextViewConnectionListener, IActiveViewAccessor
{
public IWpfTextView? ActiveView { get; private set; }
public void SubjectBuffersConnected(IWpfTextView textView, ConnectionReason reason, Collection<ITextBuffer> subjectBuffers)
{
this.ActiveView = textView;
}
public void SubjectBuffersDisconnected(IWpfTextView textView, ConnectionReason reason, Collection<ITextBuffer> subjectBuffers)
{
this.ActiveView = null;
}
}
Эта служба внедряется в пакет VSPackage как:
this.viewAccessor = this.exportProvider.GetExportedValue<IActiveViewAccessor>();
и он используется как:
var view = this.viewAccessor?.ActiveView;
Есть ли лучший и более стабильный способ получить IWpfTextView в асинхронном пакете VSPackage?
Пока что вот некоторые связанные вопросы, но не совсем то, что я ожидал:
@PerryQian-MSFT Я не был полностью уверен в «современном» или «правильном» способе доступа к активному IWpfTextView, но ваше предложение имеет смысл, спасибо. Сделанный.
После небольшой отладки и изучения я пришел к выводу, что мой первоначальный подход очень наивен. Потому что IWpfTextViewConnectionListener
срабатывает только один раз для каждого окна редактора в простом случае и не срабатывает при переключении между уже подключенными представлениями.
Поэкспериментировав с ним и проникнув в VsVim > VsAdapter.cs, я изменил IActiveViewAccessor
на это:
public interface IActiveViewAccessor
{
IWpfTextView? ActiveView { get; }
}
[Export(typeof(IActiveViewAccessor))]
internal sealed class ActiveViewAccessor : IActiveViewAccessor
{
private readonly SVsServiceProvider serviceProvider;
private readonly IVsEditorAdaptersFactoryService editorAdaptersFactoryService;
[ImportingConstructor]
public ActiveViewAccessor(
SVsServiceProvider vsServiceProvider,
IVsEditorAdaptersFactoryService editorAdaptersFactoryService)
{
this.serviceProvider = vsServiceProvider;
this.editorAdaptersFactoryService = editorAdaptersFactoryService;
}
public IWpfTextView? ActiveView
{
get
{
IVsTextManager2 textManager =
serviceProvider.GetService<SVsTextManager, IVsTextManager2>();
if (textManager == null)
{
return null;
}
int hr = textManager.GetActiveView2(
fMustHaveFocus: 1,
pBuffer: null,
grfIncludeViewFrameType: (uint)_VIEWFRAMETYPE.vftCodeWindow,
ppView: out IVsTextView vsTextView);
if (ErrorHandler.Failed(hr))
{
return null;
}
return editorAdaptersFactoryService.GetWpfTextView(vsTextView);
}
}
}
Я предлагаю вам добавить ответ о ваших советах, а не в вопросе.