Visual Studio 2010 SDK - Как разместить украшение рядом с группами комментариев XML?

У меня проблемы с поиском, как это сделать, и Visual Studio SDK Reference тоже не очень полезен.

Я пытаюсь выяснить, как получить NormalizedSnapshotSpanCollection XML комментариев. Я хочу разместить значок рядом с ними... Я не хочу, чтобы значок рядом с каждой строкой, но только рядом с первой строкой каждой группы...

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

1 ответ

Решение

Вот что я мог бы получить, я думаю, это очень похоже на то, что вам нужно. Я собираюсь обновить это с более подробной информацией, если у вас есть вопросы.

VS 2010 иконка украшения

Я начал с этого примера с веб-сайта VS 2010 SDK. Это уже довольно близко к тому, что вам нужно, но требует еще нескольких шагов.


Скачайте версию C#, распакуйте в папку, скомпилируйте. Для запуска и тестирования вам нужно перейти в Project > Properties > Debug

Вам нужно выбрать опцию "Запустить внешнюю программу" и указать путь к вашему приложению 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 из Википедии и поместил в свою временную папку.

Скомпилируйте и запустите. Вы должны увидеть логотип SO рядом с комментариями в экземпляре VS отладки.


Несколько дополнительных замечаний.

Во-первых, таким образом, вы просто начинаете работать с рабочим прототипом, вы должны переименовать классы и очистить код для ваших нужд.

Во-вторых, когда я отлаживал его, моя отладочная 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));
    }
Другие вопросы по тегам