Search code examples
visual-studio-extensionsvsixvs-extensibilityvisual-studio-sdk

Visual Studio SDK - How to add a margin glyph on command invoked?


How can I modify this sample: https://msdn.microsoft.com/en-us/library/ee361745.aspx to have glyphs added to the margin when a button I added is clicked?

I have a button which creates a special kind of breakpoint. I would like this kind to be recognized by my own margin glyph. So I wrote the GetTags method in my Tagger class as follows:

    IEnumerable<ITagSpan<MyBreakpointTag>> ITagger<MyBreakpointTag>.GetTags(NormalizedSnapshotSpanCollection spans)
    {
        if (BreakpointManager != null)
        {
            DTE2 ide = ServiceProvider.GlobalProvider.GetService(typeof(DTE)) as DTE2;
            Document document = ide.ActiveDocument;

            foreach (SnapshotSpan span in spans)
            {
                ITextSnapshot textSnapshot = span.Snapshot;
                foreach (ITextSnapshotLine textSnapshotLine in textSnapshot.Lines)
                {
                    if (BreakpointManager.IsMyBreakpointAt(document.FullName, textSnapshotLine.LineNumber + 1))
                    {
                        yield return new TagSpan<MyBreakpointTag>(new SnapshotSpan(textSnapshotLine.Start, 1),
                                new MyBreakpointTag());
                    }
                }
            }
        }
    }

However, glyphs are added after moving the cursor to a different line of code or making changes to the code. What do I have to do to have glyphs added right after the button is clicked?


Solution

  • GetTags is called by the editor whenever a layout happens, but the editor won't call it for any random reason. (Think: how would it know when to call you?) You need to raise the TagsChanged event from your tagger to say the tags for a given span changed, and then it'll call GetTags again to refresh.

    As an unrelated piece of advice: you shouldn't be using DTE.ActiveDocument in your GetTags for a few reasons:

    1. GetTags should be as fast as possible...calling DTE methods are rarely fast.
    2. Imagine you have two files open, and GetTags is called for the non-active file. That would have both files looking at the same filename which is probably bad. There's code here that shows how to fetch the file name from an ITextBuffer.