Visual Studio 2010 SDK - Как разместить украшение рядом с группами комментариев XML? - PullRequest
7 голосов
/ 14 февраля 2012

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

Я пытаюсь выяснить, как получить 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 Ответ

11 голосов
/ 22 февраля 2012

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

VS 2010 icon adornment

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


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

. Вам нужно выбрать опцию «Start External Program» и указать путь к вашему приложению VS 2010, например, C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\devenv.exe

* 1015.* В аргументах командной строки задайте: /rootsuffix Exp

Теперь вы сможете запустить его, создать какой-нибудь пример проекта в открытом VS и, если вы наберете где-нибудь шестизначное число, например 00AA00 itбудет отображаться в виде прямоугольника с соответствующим цветом.Закройте экземпляр отладочной 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));
    }
...