在quickInfoContent中使用UserControl时,QuickInfoSession会过早被取消

HJL*_*ink 5 c# wpf visual-studio vsix

首先是一些样板代码; 问题如下.

我有一个标准的QuickInfoSourceProvider:

[Export(typeof(IIntellisenseControllerProvider))]
internal sealed class QuickInfoControllerProvider : IIntellisenseControllerProvider
{
    [Import]
    private IQuickInfoBroker _quickInfoBroker = null;

    public IIntellisenseController TryCreateIntellisenseController(ITextView textView, IList<ITextBuffer> subjectBuffers)
    {
        return new QuickInfoController(textView, subjectBuffers, this._quickInfoBroker);
    }
}
Run Code Online (Sandbox Code Playgroud)

和标准的QuickInfoController:

internal sealed class QuickInfoController : IIntellisenseController
{
    private readonly IList<ITextBuffer> _subjectBuffers;
    private readonly IQuickInfoBroker _quickInfoBroker;
    private ITextView _textView;

    internal QuickInfoController(
        ITextView textView,
        IList<ITextBuffer> subjectBuffers,
        IQuickInfoBroker quickInfoBroker)
    {
        this._textView = textView;
        this._subjectBuffers = subjectBuffers;
        this._quickInfoBroker = quickInfoBroker;
        this._textView.MouseHover += (o, e) => {
            SnapshotPoint? point = GetMousePosition(new SnapshotPoint(this._textView.TextSnapshot, e.Position));
            if (point.HasValue)
            {
                ITrackingPoint triggerPoint = point.Value.Snapshot.CreateTrackingPoint(point.Value.Position, PointTrackingMode.Positive);
                if (!this._quickInfoBroker.IsQuickInfoActive(this._textView))
                {
                    this._quickInfoBroker.TriggerQuickInfo(this._textView, triggerPoint, false);
                }
            }
        };
    }
    private SnapshotPoint? GetMousePosition(SnapshotPoint topPosition)
    {
        return this._textView.BufferGraph.MapDownToFirstMatch(
            topPosition,
            PointTrackingMode.Positive,
            snapshot => this._subjectBuffers.Contains(snapshot.TextBuffer),
            PositionAffinity.Predecessor
        );
    }
}
Run Code Online (Sandbox Code Playgroud)

QuickInfoSourceProvider也是标准的:

[Export(typeof(IQuickInfoSourceProvider))]
internal sealed class QuickInfoSourceProvider : IQuickInfoSourceProvider
{
    public IQuickInfoSource TryCreateQuickInfoSource(ITextBuffer buffer)
    {
        Func<QuickInfoSource> sc = delegate () {
            return new QuickInfoSource(buffer);
        };
        return buffer.Properties.GetOrCreateSingletonProperty(sc);
    }
}
Run Code Online (Sandbox Code Playgroud)

现在事情变得有趣了:我没有在quickInfoContent中添加一个普通字符串,而是传入一个UserControl(BugWindow); 但仍然很标准:

internal sealed class QuickInfoSource : IQuickInfoSource
{
    private readonly ITextBuffer _sourceBuffer;
    public QuickInfoSource(ITextBuffer buffer)
    {
        this._sourceBuffer = buffer;
    }
    public void AugmentQuickInfoSession(IQuickInfoSession session, IList<object> quickInfoContent, out ITrackingSpan applicableToSpan)
    {
        var snapshot = this._sourceBuffer.CurrentSnapshot;
        var triggerPoint = (SnapshotPoint)session.GetTriggerPoint(snapshot);
        applicableToSpan = snapshot.CreateTrackingSpan(new SnapshotSpan(triggerPoint, triggerPoint), SpanTrackingMode.EdgeInclusive);
        quickInfoContent.Add(new BugWindow());
    }
}
Run Code Online (Sandbox Code Playgroud)

BugWindow.xaml包含一个扩展器,这个扩展器就是故障的开始.首先是代码:

<UserControl x:Class="BugWindow"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             x:Name="MainWindow">
    <Expander GotMouseCapture="GotMouseCapture_Click" IsExpanded="False">Blah</Expander>
</UserControl>
Run Code Online (Sandbox Code Playgroud)

BugWindow.xaml.cs包含一些代码可以帮助我理解问题.我的第一个想法是防止鼠标事件冒泡到VS,但这些实验没有帮助......

public partial class BugWindow : UserControl
{
    public BugWindow()
    {
        InitializeComponent();

        this.MainWindow.MouseLeftButtonDown += (o, i) => 
        {
            //i.Handled = true; // dont let the mouse event from inside this window bubble up to VS
        }; 

        this.MainWindow.PreviewMouseLeftButtonDown += (o, i) =>
        {
            //i.Handled = true; // if true then no event is able to bubble to the gui
        };
    }

    private void GotMouseCapture_Click(object sender, RoutedEventArgs e)
    {
        //e.Handled = true;
    }
}
Run Code Online (Sandbox Code Playgroud)

有效的方法是:如果将鼠标悬停在关键字上,我的BugWindow会出现,并且扩展器会关闭(因为它默认是关闭的).如果单击扩展器,它将打开并显示文本"Blah".

错误:如果您打开扩展器并向下滚动,当工具提示适用于(applicableSpan)的范围超出可见窗口时,工具提示将消失.我们现在处于"错误状态".如果将鼠标悬停在任何关键字上,我的BugWindow将会出现.如果单击扩展器,窗口将错误地消失.事实上,quickInfoSession将被取消,就像你点击没有关键字的地方一样,这被解释为解雇会话.按钮具有相同的错误行为.

问题:如何调试:鼠标事件丢失或被劫持.我想知道为什么会这样.但说实话,我只是喜欢我的扩展器,表现得像预期的那样.

编辑:有关此错误的最小github仓库可以在https://github.com/HJLebbink/vsix-bug-quickinfosession找到.请使用github问题寻求帮助.