Recently, VS2010 Extension has been mentioned frequently on the Visual Studio Blog ( http://blogs.msdn.com/visualstudio/ ), so I wanted to look into the documentation to study it. However, after searching for a long time, there was no complete introduction to this topic. So, I had to look for the content provided by the template on the VS IDE and the explanation on the Visual Studio Blog. While using Reflector, I scribbled some codes and prepared for a live practice. However, I felt that the Extension created by this template was too simple. I happened to see that AxTool ( http://www.axtools.com/products-vs2010-extensions.php ) has a code editor extension, which is also a VS Extension, so I followed this and made it step by step.
First of all, to create a VS Extension project, you need to install the VS2010 SDK, which is currently the Beta2 version. You can download it here: http://go.microsoft.com/fwlink/?LinkID=165597 ), here I use the Editor The project created by the Text Adornment template, well, I will not write in detail how to create your own Extension project through the template. If you are not familiar with this, you can refer to this post by Quan To - Building and publishing an extension for Visual Studio 2010.
After the project is built, TextViewCreationListener will be automatically generated. The IWpfTextViewCreationListener interface is implemented here, and the IWpfTextViewCreationListener object is exported through MEF:
[TextViewRole("DOCUMENT")] [Export(typeof(IWpfTextViewCreationListener))] [ContentType("text")] internal sealed class PETextViewCreationListener : IWpfTextViewCreationListener { void IWpfTextViewCreationListener.TextViewCreated(IWpfTextView textView) { //... } }
In this way, VS will call the IWpfTextViewCreationListener.TextViewCreated method at the appropriate time to notify the text editing status change.
In order to float your own toolbar, you also need to export an AdornmentLayerDefinition and customize the display position and order of this Adornment layer through the Order Attribute:
[Name("QuickToolbarAdornmentLayer")] [Order(After = "Text")] [Export(typeof(AdornmentLayerDefinition))] public AdornmentLayerDefinition QuickToolbarLayerDefinition { get; set; }
The Name Attribute here is very important. We will rely on it to obtain our AdornmentLayer in future code:
this._adornmentLayer = this._textView.GetAdornmentLayer("QuickToolbarAdornmentLayer");
Going a step further, let’s go back to IWpfTextViewCreationListener.TextViewCreated. Through here, you can get an IWpfTextView.
This is the goal and presentation of all operations. In addition, its Closed, LayoutChanged, MouseHovered, SelectionChanged and other events need to be hung in order to respond to user behavior.
Since we want to operate the code through the toolbar, we need to import IEditorOperationsFactoryService through MEF:
[Import] internal IEditorOperationsFactoryService EditorOperationsFactoryService { get; set; }
In this way, IEditorOperations can be obtained through IEditorOperationsFactoryService.GetEditorOperations(ITextView) in IWpfTextViewCreationListener.TextViewCreated. With it, you can edit the code conveniently and quickly.
Next, we need to implement the toolbar interface. I won’t go into details about this. Just create a UserControl and put a ToolBar in it. So when and where to display this ToolBar? This depends on the SelectionChanged event of IWpfTextView. The event mentioned above is used here.
code
1 private void MayBeAdornmentShowCondition() 2 { 3 if (!this._textView.Selection.IsEmpty) 4 { 5 SnapshotPoint startPos = this._textView.Selection.Start.Position; 6 SnapshotPoint endPos = this._textView.Selection.End.Position; 7 IWpfTextViewLine textViewLineContainingBufferPosition = this._textView.GetTextViewLineContainingBufferPosition(startPos); 8 TextBounds characterBounds = textViewLineContainingBufferPosition.GetCharacterBounds(startPos); 9 TextBounds bounds2 = this._textView.GetTextViewLineContainingBufferPosition(endPos). GetCharacterBounds(endPos);10 if (this._fromMouseHover)11 {12 this._mustHaveAdornmentDisplayed = true;13 }14 else15 {16 PELeftButtonMouseProcessor property = null;17 try18 {19 property = this._textView.Properties.GetProperty<PELeftButtonMouseProcessor>(typeof(PELeftButtonMouseProcessor));20 }21 catch22 {23 }24 this._mustHaveAdornmentDisplayed = (property != null)25 && (property.IsLeftButtonDown26 || ((DateTime.Now - property.LastLeftButtonDownTime).TotalMilliseconds < 400.0));27 }28 if (this._mustHaveAdornmentDisplayed)29 {30 TextBounds selectionBounds = !this._textView.Selection.IsReversed ? bounds2 : characterBounds;31 int offset = 7;32 double top = selectionBounds.Top + (!this._textView.Selection.IsReversed ? (offset + textViewLineContainingBufferPosition.Height) : (-offset - this ._adornmentUI.ActualHeight));33 if (top < 0.0)34 {35 top = 0.0;36 }37 double left = characterBounds.Left + ((bounds2.Left - characterBounds.Left) / 2.0);38 if ((left + this._adornmentUI.ActualWidth) > this._textView.ViewportWidth)39 {40 left = this._textView.ViewportWidth - this._adornmentUI.ActualWidth;41 }42 Canvas.SetTop(this._adornmentUI, top);43 Canvas.SetLeft( this._adornmentUI, left);44 long chars = 0L;45 try46 {47 chars = this._textView.Selection.SelectedSpans[0].Span.Length;48 }49 catch50 {51 }52 this._adornmentUI.SetStatus(chars) ;53 this.RenderSelectionPopup();54 }55 }56 else57 {58 this._mustHaveAdornmentDisplayed = false;59 this._adornmentLayer.RemoveAdornmentsByTag(this._adornmentTag);60 }61 }62 63 private void RenderSelectionPopup()64 {65 if ( this._mustHaveAdornmentDisplayed)66 {67 IAdornmentLayerElement element = null;68 try69 {70 element = this._adornmentLayer.Elements.First<IAdornmentLayerElement>(71 (IAdornmentLayerElement ile) => ile.Tag.ToString() == this._adornmentTag); 72 }73 catch (InvalidOperationException)74 {75 }76 if (element == null)77 {78 this._adornmentLayer.AddAdornment(this._textView.Selection.SelectedSpans[0], this._adornmentTag, this._adornmentUI);79 } 80 this._timer.Stop();81 this._timer.Start();82 }83 }84 85 private void selection_SelectionChanged(object sender, EventArgs e)86 {87 this._fromMouseHover = false;88 this.MayBeAdornmentShowCondition(); 89}90
Then it should be noted that when handling the Closed event of IWpfTextView, you must remember to cancel all the finishing work such as this event.
semi.png(12.70 K)
2010-1-25 16:42:05
toolbar.png(15.64 K)
2010-1-25 16:42:05
Next, compile the project and package VSIX. The main features currently implemented are:
1. When you select a piece of text in the code editor and move the mouse to the text area, QuickToolbar will "float" next to the text in a semi-transparent manner.
2. When the mouse moves to the QuickToolbar area, the QuickToolbar will become opaque, and the buttons on it will respond to mouse actions.
3. Currently supported operations are:
Cut
Copy
Paste
Delete
Decrease Indent
Increase Indent
Comment code (Comment)
Uncomment
etc.
VSIX and source code download and installation methods are in the GCDN forum: [VS2010 Extension] Floating Toolbar ( http://gcdn.grapecity.com/showtopic-345.html )
To be the apostrophe which changed “Impossible” into “I'm possible”
-------------------------------------------------- --
WinkingZhang's Blog ( http://winkingzhang.cnblogs.com )
GCDN( http://gcdn.grapecity.com/cs )