Walkthrough: Creating a Margin Glyph
You can customize the appearance of editor margins by using custom editor extensions. This walkthrough puts a custom glyph on the indicator margin whenever the word "todo" appears in a code comment.
To complete this walkthrough, you must install the Visual Studio 2012 SDK.
Note
|
|---|
|
For more information about the Visual Studio SDK, see Extending Visual Studio Overview. To find out how to download the Visual Studio SDK, see Visual Studio Extensibility Developer Center on the MSDN Web site. |
To create a MEF project
-
Create a Visual C# or Visual Basic Editor Classifier project. Name the solution TodoGlyphTest.
-
Open the Source.extension.vsixmanifest file in the VSIX Manifest Editor.
-
Make sure that the Content heading contains a MEF Component content type and that the Path is set to TodoGlyphTest.dll.
-
Save and close Source.extension.vsixmanifest.
-
Remove the existing class files.
Define a glyph by implementing the IGlyphFactory interface.
To define the glyph
-
Add a class file and name it TodoGlyphFactory.
-
Add the following imports.
Imports System.ComponentModel.Composition Imports System.Windows Imports System.Windows.Shapes Imports System.Windows.Media Imports System.Windows.Controls Imports Microsoft.VisualStudio.Text Imports Microsoft.VisualStudio.Text.Editor Imports Microsoft.VisualStudio.Text.Formatting Imports Microsoft.VisualStudio.Text.Tagging Imports Microsoft.VisualStudio.Utilities
-
Add a class named TodoGlyphFactory that implements IGlyphFactory.
-
Add a private field that defines the dimensions of the glyph.
-
Implement GenerateGlyph by defining the glyph user interface (UI) element. TodoTag is defined later in this walkthrough.
Public Function GenerateGlyph(ByVal line As IWpfTextViewLine, ByVal tag As IGlyphTag) As System.Windows.UIElement Implements IGlyphFactory.GenerateGlyph ' Ensure we can draw a glyph for this marker. If tag Is Nothing OrElse Not (TypeOf tag Is TodoTag) Then Return Nothing End If Dim ellipse As Ellipse = New Ellipse() ellipse.Fill = Brushes.LightBlue ellipse.StrokeThickness = 2 ellipse.Stroke = Brushes.DarkBlue ellipse.Height = m_glyphSize ellipse.Width = m_glyphSize Return ellipse End Function
-
Add a class named TodoGlyphFactoryProvider that implements IGlyphFactoryProvider. Export this class with a NameAttribute of "TodoGlyph", an OrderAttribute of After VsTextMarker, a ContentTypeAttribute of "code", and a TagTypeAttribute of TodoTag.
-
Implement the GetGlyphFactory method by instantiating the TodoGlyphFactory.
Define the relationship between the UI element that you defined in the previous steps and the indicator margin by creating a tag type and tagger, and exporting it by using a tagger provider.
To define a todo tag and tagger
-
Add a new class to the project and name it TodoTagger.
-
Add the following imports.
Imports System Imports System.Collections.Generic Imports System.ComponentModel.Composition Imports Microsoft.VisualStudio.Text Imports Microsoft.VisualStudio.Text.Tagging Imports Microsoft.VisualStudio.Text.Editor Imports Microsoft.VisualStudio.Text.Classification Imports Microsoft.VisualStudio.Utilities
-
Add a class named TodoTag.
-
Modify the class named TodoTagger that implements ITagger(Of T) of type TodoTag.
-
To the TodoTagger class, add private fields for an IClassifier and for the text to find in the classification spans.
-
Add a constructor that sets the classifier.
-
Implement the GetTags method by finding all the classification spans whose names include the word "comment" and whose text includes the search text. Whenever the search text is found, yield back a new TagSpan(Of T) of type TodoTag.
Private Function GetTags(ByVal spans As NormalizedSnapshotSpanCollection) As IEnumerable(Of ITagSpan(Of TodoTag)) Implements ITagger(Of TodoTag).GetTags Dim list As List(Of ITagSpan(Of TodoTag)) list = New List(Of ITagSpan(Of TodoTag))() For Each span As SnapshotSpan In spans 'look at each classification span \ For Each classification As ClassificationSpan In m_classifier.GetClassificationSpans(span) 'if the classification is a comment If classification.ClassificationType.Classification.ToLower().Contains("comment") Then 'if the word "todo" is in the comment, 'create a new TodoTag TagSpan Dim index As Integer = classification.Span.GetText().ToLower().IndexOf(m_searchText) If index <> -1 Then list.Add(New TagSpan(Of TodoTag)(New SnapshotSpan(classification.Span.Start + index, m_searchText.Length), New TodoTag())) End If End If Next classification Next span Return list End Function
-
Declare a TagsChanged event.
-
Add a class named TodoTaggerProvider that implements ITaggerProvider, and export it with a ContentTypeAttribute of "code" and a TagTypeAttribute of TodoTag.
-
Import the IClassifierAggregatorService.
-
Implement the CreateTagger(Of T) method by instantiating the TodoTagger.
Public Function CreateTagger(Of T As Microsoft.VisualStudio.Text.Tagging.ITag)(ByVal buffer As Microsoft.VisualStudio.Text.ITextBuffer) As Microsoft.VisualStudio.Text.Tagging.ITagger(Of T) Implements Microsoft.VisualStudio.Text.Tagging.ITaggerProvider.CreateTagger If buffer Is Nothing Then Throw New ArgumentNullException("buffer") End If Return TryCast(New TodoTagger(AggregatorService.GetClassifier(buffer)), ITagger(Of T)) End Function
To test this code, build the TodoGlyphTest solution and run it in the experimental instance.
To build and test the TodoGlyphTest solution
-
Build the solution.
-
Run the project by pressing F5. A second instance of Visual Studio is instantiated.
-
Make sure that the indicator margin is showing. (On the Tools menu, click Options. On the Text Editor page, make sure that Indicator margin is selected.)
-
Open a code file that has comments. Add the word "todo" to one of the comment sections.
-
A light blue circle that has a dark blue outline should appear in the indicator margin to the left of the code window.
Note