Visual Studio 2010 SDK -- 如何在XML注释组旁边放置修饰?

7

我在寻找如何获取XML注释的NormalizedSnapshotSpanCollection,但是Visual Studio SDK参考文档并没有提供很好的帮助。

我想在这些注释旁边放置一个图标... 我不想在每一行旁边都放一个图标,而只想在每个组的第一行旁边放置一个图标...

///<summary>SomeXML Comment</summary>   [ICON]
///<remarks>some remarks</remarks>
public void Foo()
{
    ///Some false XML comment line that does not get an icon.
}

很遗憾,我不认为我能给你一个完整的答案,但是我可以指出你至少需要了解IAdornmentLayer(这是如何在视图上绘制的)。视图本身是IWpfTextView类型的。这是在屏幕上绘制实际图标的部分。确定确切的位置我无法帮助你,因为我不知道如何发现xml注释块的右上角,更不用说一个特定的方法/字段/属性/类等上面的注释块了。 - myermian
为什么需要NormalizedSnapshotSpanCollection?你知道吗?你可以从IWpfTextView获取当前编辑缓冲区的所有行,并使用简单的正则表达式查找所有与///<summary>whatever</summary>行匹配的内容,然后在该行上添加一个图标(在你的装饰层中),坐标可以自由指定。 - Jesus Salas
不,我对此一无所知。我只是看到一个使用了NormalizedSnapshotSpancollection的示例,因此我认为我需要它...基本上,任何能够为我提供所需坐标且不会出现错误匹配的东西,这样我就可以在想要的位置放置图标。 - michael
1个回答

11

这是我能获取到的内容,我认为它与您所需的内容非常相似。如果您有问题,我将通过更新更多详细信息来解决。

VS 2010图标修饰

我是从VS 2010 SDK网站的这个示例开始的。它已经非常接近您所需的内容,但需要进行几个步骤。


下载C#版本,解压到一个文件夹中,编译。要运行它并测试,您需要转到项目>属性>调试

您需要选择 "启动外部程序 "选项,并设置路径到您的 VS 2010 应用程序,例如:C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\devenv.exe

在命令行参数中设置:/rootsuffix Exp

现在,您应该能够运行它,在打开的 VS 中创建一些示例项目,如果您在任何地方键入六位数字,如00AA00,它将显示为具有相应颜色的矩形。关闭调试的 VS 实例。


现在让我们编辑一些代码。在 ColorAdornmentTagger.cs 中注释掉定义 #define HIDING_TEXT。这将显示修饰品在文本旁边而不是替换它。

在同一文件中,您需要找到初始化SnapshotSpan adornmentSpan的位置,并将该行更改为:

SnapshotSpan adornmentSpan = new SnapshotSpan(colorTagSpans[0].End, 0);

这将在文本范围之后放置修饰,而不是之前。


ColorTagger.cs中。更改构造函数中的正则表达式,使构造函数现在如下所示

    internal ColorTagger(ITextBuffer buffer)
        : base(
        buffer, 
        new[] { new Regex(@"/// <summary>.*", RegexOptions.Compiled | RegexOptions.CultureInvariant | RegexOptions.IgnoreCase) }
        )
    {
    }

这将设置正则表达式以识别方法注释行。

在这个类中的其它方法我们不会用到,你可以将它们注释掉或者返回一些随机颜色。


在 'ColorAdornment.cs' 中。这是 WPF 控件本身的修饰。首先将基类从 Button 更改为 ContentControl。更改类的构造函数为

    internal ColorAdornment(ColorTag colorTag)
    {
        BitmapImage image = new BitmapImage(); 
        using (FileStream stream = File.OpenRead("c:\\temp\\sologo.png")) 
        { 
            image.BeginInit(); 
            image.StreamSource = stream; 
            image.CacheOption = BitmapCacheOption.OnLoad; 
            image.EndInit(); 
        }

        this.Content = new Image() { Margin = new Thickness(20,0,0,0), Width = 100, Height = 30, Source = image };
    }

您可以更改图像路径为您所需的图像路径。我只是从维基百科下载了SO标志并将其放入我的临时文件夹中。

编译并运行。您应该能够在调试VS实例的注释旁边看到SO标志。


一些额外的说明。

首先,通过这种方式,您只需获得一个可工作的原型,然后应根据您的需求重命名类并清理代码。

其次,在我调试它时,我的调试VS不时会冻结。我认为这可能与IntraTextAdornmentTagger.cs中的锁有关。

如果您也遇到了冻结,请尝试以以下方式更新此方法:

    protected void InvalidateSpans(IList<SnapshotSpan> spans)
    {
        if (spans.Count == 0)
            return;
        bool wasEmpty = false;
        lock (this.invalidatedSpans)
        {
            wasEmpty = this.invalidatedSpans.Count == 0;
            this.invalidatedSpans.AddRange(spans);
        }

        if (wasEmpty)
            this.view.VisualElement.Dispatcher.BeginInvoke(new Action(AsyncUpdate));
    }

并且可以通过以下方式进行AsyncUpdate:

    private void AsyncUpdate()
    {
        // Store the snapshot that we're now current with and send an event
        // for the text that has changed.
        if (this.snapshot != this.view.TextBuffer.CurrentSnapshot)
        {
            this.snapshot = this.view.TextBuffer.CurrentSnapshot;

            Dictionary<SnapshotSpan, TAdornment> translatedAdornmentCache = new Dictionary<SnapshotSpan, TAdornment>();

            foreach (var keyValuePair in this.adornmentCache)
                translatedAdornmentCache.Add(keyValuePair.Key.TranslateTo(this.snapshot, SpanTrackingMode.EdgeExclusive), keyValuePair.Value);

            this.adornmentCache = translatedAdornmentCache;
        }

        List<SnapshotSpan> spansCopy;
        lock (this.invalidatedSpans)
        {
            spansCopy = this.invalidatedSpans.ToList();
            this.invalidatedSpans.Clear();
        }

        List<SnapshotSpan> translatedSpans = spansCopy.Select(s => s.TranslateTo(this.snapshot, SpanTrackingMode.EdgeInclusive)).ToList();

        if (translatedSpans.Count == 0)
            return;

        var start = translatedSpans.Select(span => span.Start).Min();
        var end = translatedSpans.Select(span => span.End).Max();

        RaiseTagsChanged(new SnapshotSpan(start, end));
    }

嗯,这绝对是一个很好的起点。我希望有一些算法可以检测到注释块位于有效的类、枚举、结构、属性、字段、方法等上方,但我认为这个算法已经接近我现在所能得到的了。它存在一些漏洞,因为它依赖于 /// <summary>*,我可以将其放在其他地方并获得错误的结果(我知道这样做没有意义)。无论如何,非常感谢你的帮助,额外奖励200分。 - michael
还有,为什么我需要在 devenv.exe 命令中使用 "/rootsuffix Exp" 参数? - michael
@michael:谢谢!/rootsuffix Exp是为了保护默认的VS不受你的实验影响。http://msdn.microsoft.com/en-us/library/bb166560(v=VS.80).aspx - Massimiliano
@michael:你说得没错,关于错误的正面结果(虽然很少可能在其他任何地方看到该字符串),您可以尝试想出更好的正则表达式来匹配类名、枚举、字段等。另一种选择是探索SDK文档,我认为有一种方法可以使用编辑器对程序中哪个部分属于哪种类型的知识。也许有一种方法可以检测哪里是字段或类的注释... - Massimiliano

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接