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 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));
}