如何在 VS2019 扩展(MEF)中激活 IWpfTextView
How to get active IWpfTextView in VS2019 extension (MEF)
我正在尝试在 VS2019 扩展中获取活动的 C# 编辑器 IWpfTextView。我正在使用小型 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;
有没有更好更稳定的方式在异步VSPackage中获取IWpfTextView?
到目前为止,这里有一些相关的问题,但并不完全符合我的预期:
- How can I get IWpfTextView for EnvDte.ActiveDocument? (2013)
- Access current code pane in Visual Studio Extension (2012)
经过一番调试和探索,我得出结论,我最初的做法非常幼稚。因为在简单情况下 IWpfTextViewConnectionListener
每个编辑器 window 只触发一次,并且在已连接的视图之间切换时不会触发。
在尝试并潜入 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);
}
}
}
我正在尝试在 VS2019 扩展中获取活动的 C# 编辑器 IWpfTextView。我正在使用小型 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;
有没有更好更稳定的方式在异步VSPackage中获取IWpfTextView?
到目前为止,这里有一些相关的问题,但并不完全符合我的预期:
- How can I get IWpfTextView for EnvDte.ActiveDocument? (2013)
- Access current code pane in Visual Studio Extension (2012)
经过一番调试和探索,我得出结论,我最初的做法非常幼稚。因为在简单情况下 IWpfTextViewConnectionListener
每个编辑器 window 只触发一次,并且在已连接的视图之间切换时不会触发。
在尝试并潜入 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);
}
}
}