最近VS2010 Extension在Visual Studio Blog( http://blogs.msdn.com/visualstudio/ )上提得很頻繁,於是也想翻來文檔研究研究,結果居然找了半天,居然沒有一丁點完整介紹這一塊的,於是,只好自己找個VS IDE上的模板提供的內容和Visual Studio Blog上的講解,一邊Reflector參演,一邊塗鴉一些代碼,準備實彈演練一下,但是覺得這個模板建出來的Extension也太簡單了,剛好看到AxTool( http://www.axtools.com/products-vs2010-extensions.php )有一個程式碼編輯器擴展,也是VS Extension的,於是就照著這個,自己一步一步做一下。
首先,要建立VS Extension工程,你需要安裝VS2010 SDK,目前是Beta2版本,你可以到這裡可以下載: http ://go.microsoft.com/fwlink/?LinkID=165597 ),這裡我是透過 Editor Text Adornment範本所建立的工程,嗯,我就不詳細寫如何透過範本建立自己Extension工程了,如果你不熟悉這裡,可以參考Quan To的這篇文章-Building and publishing an extension for Visual Studio 2010。
建好工程以後,會自動產生TextViewCreationListener,這裡實作了IWpfTextViewCreationListener接口,並透過MEF導出IWpfTextViewCreationListener物件:
[TextViewRole("DOCUMENT")] [Export(typeof(IWpfTextViewCreationListener))] [ContentType("text")] internal sealed class PETextViewCreationListener : IWpfTextViewCreationListener { void IWpfTextViewCreationListener : IWpfTextViewCreationListener { void IWpfTextViewCreationListener : IWpfTextViewCreationListener { void IWpfTextViewCreationListener : IWpfTextViewCreationListener { void IWpfTextViewCreationList
這樣VS就會在適當的時候呼叫IWpfTextViewCreationListener.TextViewCreated方法來通知文字編輯的狀態改變。
為了實現浮動一個自己的工具列,這裡還需要匯出一個AdornmentLayerDefinition,並透過Order Attribute來自訂這個Adornment層的顯示位置和順序:
[Name("QuickToolbarAdornmentLayer")] [Order(After = "Text")] [Export(typeof(AdornmentLayerDefinition))] public AdornmentLayerDefinition QuickToolbarLayerDefinition { get; set; }
這裡的Name Attribute很重要,以後的程式碼要取得我們的AdornmentLayer就得靠它了:
this._adornmentLayer = this._textView.GetAdornmentLayer("QuickToolbarAdornmentLayer");
扯得遠了,回到IWpfTextViewCreationListener.TextViewCreated,透過這裡,可以得到一個IWpfTextView,
這是所有操作的目標和展現,另外,還需要掛他的Closed、LayoutChanged、MouseHovered、SelectionChanged等事件,以回應使用者行為。
由於我們要透過工具列操作程式碼,所以需要透過MEF匯入IEditorOperationsFactoryService:
[Import] internal IEditorOperationsFactoryService EditorOperationsFactoryService { get; set; }
這樣就可以在IWpfTextViewCreationListener.TextViewCreated中透過IEditorOperationsFactoryService.GetEditorOperations(ITextView)來取得IEditorOperations,有了它,就可以方便快速的編輯程式碼了。
接下來要實作工具列的介面,這個就不多說了,建造一個UserControl,裡面放上ToolBar就搞定了。那麼何時何地顯示這個ToolBar呢?這就要依賴IWpfTextView的SelectionChanged事件了,上面提到會掛這個事件就是為這裡用的。
程式碼
1 private void MayBeAdornmentShowCondition() 2 { 3 if (!this._textView.Selection.IsEmpty) 4 { 5 SnapshotPoint startPos = this._textView.Selection.Start.Position; 6 SnapshotPoint endPViewos = this_text. 7 IWpfTextViewLine textViewLineContainingBufferPosition = this._textView.GetTextViewLineContainingBufferPosition(startPos); 8 TextBounds characterBounds = textViewLineContainingBufferPosition.GetCharacterBounds(P圓. Position(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<PELeftButton {19 property = this._textView.Properties.GetProperty<PELeftButton this._mustHaveAdornmentDisplayed = (property != null)25 && (property.IsLeftButtonDown26 || ((DateTime.Now - property.LastLeftButtonDownTime).TotalMilliseconds < 400.0)); Bounds = !this._textView.Selection.IsReversed ? bounds2 : characterBounds;31 int offset = 7;32 double top = selectionBounds.Top + (!this._textView.Selection.IsReversed ? (offset + textViewLineContainingBufferv. ._adornmentUI.ActualHeight));33 if (top < 0.0)34 {35 top = 0.0;36 }37 double left = characterBounds.Left + ((bounds2.Left - characterBounds.Left) / 2.0); + this._adornmentUI.ActualWidth) > this._textView.ViewportWidth)39 {40 left = this._textView.ViewportWidth - this._adornmentUI.ActualWidth;41 }42 Canvas.SetTop(this._adornmentUI.ActualWidth;41 }42 Canvas.SetTop(this._adornmentUI, top); 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.Setus( ;53 this.RenderSelectionPopup();54 }55 }56 else57 {58 this._mustHaveAdornmentDisplayed = false;59 this._adornmentLayer.RemoveAdornmentsByTag(this._adornmentTag);60 }61 }62 6063(Fid v. this._mustHaveAdornmentDisplayed)66 {67 IAdornmentLayerElement element = null;68 try69 {70 element = this._adornmentLayer.Elements.First<IAdornmentLayerElement>(==71 (IAdornmentLayer.Elements.First<IAdornmentLayerElement>(==71 (IAdornmentLayerElementElement轉) = ile. 72 }73 catch (InvalidOperationException)74 {75 }76 if (element == null)77 {78 this._adornmentLayer.AddAdornment(this._textView.Selection.SelectedSpans[0], this._adornmentTag, this._textView.Selection.SelectedSpans[0], this._adornmentTag, this.7dornmentTagUI); 。 89 }90
然後要注意的是IWpfTextView的Closed事件處理要記得取消所有掛這個事件等等收尾工作。
semi.png(12.70 K)
2010-1-25 16:42:05
toolbar.png(15.64 K)
2010-1-25 16:42:05
接下來編譯工程,打包VSIX就完成了,目前實現的主要Feature:
1.在程式碼編輯器中選擇一段文字,並將滑鼠移到文字區域時,QuickToolbar會以半透明的方式「浮」文字的旁邊。
2.當滑鼠移到QuickToolbar區域,QuickToolbar會變成不透明,其上的按鈕會回應滑鼠動作。
3.目前支援的操作有:
剪切(Cut)
複製(Copy)
貼上(Paste)
刪除(Delete)
減小縮排(Decrease Indent)
增加縮排(Increase Indent)
註解程式碼(Comment)
取消註釋(Uncomment)
等等
VSIX和原始碼下載以及安裝方法在GCDN論壇: [VS2010擴展]浮動工具列( 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 )