网站首页 > 书籍教程 > ASP教程 > VS2010 Extension实践

VS2010 Extension实践

  • 作者:互联网
  • 时间:2010-01-27 18:39:39

最近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 IW***extViewCreationListener.TextViewCreated(IWpfTextView textView)        {            //*** ;       }    }
这样VS就会在合适的时候调用IW***extViewCreationListener.TextViewCreated方法来通知文字编辑的状态改变。

为了实现浮动一个自己的工具栏,这里还需要导出一个AdornmentLayerDefinition,并通过Order Attribute来定制这个Adornment层的显示位置和次序:

        [Name("QuickToolbarAdornmentLayer")]        [Order(After = "Text")]        [Export(typeof(AdornmentLayerDefinition))]        public AdornmentLayerDefinition QuickToolbarLayerDefinition        {            get;            set;        }
这里的Name Attribute很重要,以后的代码中要获取我们的AdornmentLayer就得靠它了:

th***_adornmentLayer = th***_textView.GetAdornmentLayer("QuickToolbarAdornmentLayer");


扯得远了,回到IW***extViewCreationListener.TextViewCreated,通过这里,可以得到一个IWpfTextView,

这是所有操作的目标和展现,另外,还需要挂他的Closed、LayoutChanged、MouseHovered、SelectionChanged等事件,以响应用户行为。

由于我们要通过工具栏操作代码,所以需要通过MEF导入IEditorOperationsFactoryService:

        [Import]        internal IEditorOperationsFactoryService EditorOperationsFactoryService        {            get;            set;        }
这样就可以在IW***extViewCreationListener.TextViewCreated中通过IE***orOperationsFactoryService.GetEditorOperations(ITextView)来获得IEditorOperations,有了它,就可以方便快捷的编辑代码了。

接下来要实现工具栏的界面,这个就不多说了,建一个UserControl,里面放上ToolBar就搞定了。那么何时何地显示这个ToolBar呢?这就要依赖IWpfTextView的SelectionChanged事件了,上面提到会挂这个事件就是为这里用的。

代码
1                 private void MayBeAdornmentShowCondition() 2                 { 3                     if (!th***_textView.Selection.IsEmpty) 4                     { 5                         SnapshotPoint startPos = th***_textView.Selection.Start.Position; 6                         SnapshotPoint endPos = th***_textView.Selection.End.Position; 7                         IWpfTextViewLine textViewLineContainingBufferPosition = th***_textView.GetTextViewLineContainingBufferPosition(startPos); 8                         TextBounds characterBounds = te***iewLineContainingBufferPosition.GetCharacterBounds(startPos); 9                         TextBounds bounds2 = th***_textView.GetTextViewLineContainingBufferPosition(endPos).GetCharacterBounds(endPos);10                         if (th***_fromMouseHover)11                         {12                             th***_mustHaveAdornmentDisplayed = true;13                         }14                         else15                         {16                             PELeftButtonMouseProcessor property = null;17                             try18                             {19                                 property = th***_textView.Properties.GetProperty(typeof(PELeftButtonMouseProcessor));20                             }21                             catch22                             {23                             }24                             th***_mustHaveAdornmentDisplayed = (property != null)25                                 && (pr***rty.IsLeftButtonDown26 ;                                || ((Da***ime.Now - pr***rty.LastLeftButtonDownTime).TotalMilliseconds < 400.0));27                         }28                         if (th***_mustHaveAdornmentDisplayed)29                         {30                             TextBounds selectionBounds = !th***_textView.Selection.IsReversed ? bounds2 : characterBounds;31                             int offset = 7;32                             double top = se***tionBounds.Top + (!th***_textView.Selection.IsReversed ? (offset + te***iewLineContainingBufferPosition.Height) : (-offset - th***_adornmentUI.ActualHeight));33                             if (top < 0.0)34                             {35                                 top = 0.0;36                             }37                             double left = ch***cterBounds.Left + ((bo***s2.Left - ch***cterBounds.Left) / 2.0);38                             if ((left + th***_adornmentUI.ActualWidth) > th***_textView.ViewportWidth)39                             {40                                 left = th***_textView.ViewportWidth - th***_adornmentUI.ActualWidth;41                             }42                             Ca***s.SetTop(th***_adornmentUI, top);43                             Ca***s.SetLeft(th***_adornmentUI, left);44                             long chars = 0L;45                             try46                             {47                                 chars = th***_textView.Selection.SelectedSpans[0].S***.Length;48                             }49                             catch50                             {51                             }52                             th***_adornmentUI.SetStatus(chars);53                             th***RenderSelectionPopup();54                         }55                     }56                     else57                     {58                         th***_mustHaveAdornmentDisplayed = false;59                         th***_adornmentLayer.RemoveAdornmentsByTag(th***_adornmentTag);60                     }61                 }62 63                 private void RenderSelectionPopup()64                 {65                     if (th***_mustHaveAdornmentDisplayed)66                     {67                         IAdornmentLayerElement element = null;68                         try69                         {70                             element = th***_adornmentLayer.Elements.First(71                                 (IAdornmentLayerElement ile) => il***ag.ToString() == th***_adornmentTag);72                         }73                         catch (InvalidOperationException)74                         {75                         }76                         if (element == null)77                         {78                             th***_adornmentLayer.AddAdornment(th***_textView.Selection.SelectedSpans[0], th***_adornmentTag, th***_adornmentUI);79                         }80                         th***_timer.Stop();81                         th***_timer.Start();82                     }83                 }84 85                 private void selection_SelectionChanged(object sender, EventArgs e)86                 {87                     th***_fromMouseHover = false;88                     th***MayBeAdornmentShowCondition();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)