VS2010 Extension实践(1)

最近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.TextViewCreated(IWpfTextView textView)
        {
            //...
        }
}

这样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 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                         else
15                         {
16                             PELeftButtonMouseProcessor property = null;
17                             try
18                             {
19                                 property = this._textView.Properties.GetProperty<PELeftButtonMouseProcessor>(typeof(PELeftButtonMouseProcessor));
20                             }
21                             catch
22                             {
23                             }
24                             this._mustHaveAdornmentDisplayed = (property != null)
25                                 && (property.IsLeftButtonDown
26                                 || ((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                             try
46                             {
47                                 chars = this._textView.Selection.SelectedSpans[0].Span.Length;
48                             }
49                             catch
50                             {
51                             }
52                             this._adornmentUI.SetStatus(chars);
53                             this.RenderSelectionPopup();
54                         }
55                     }
56                     else
57                     {
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                         try
69                         {
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                 }

然后要注意的是IWpfTextView的Closed事件处理要记得取消所有挂这个事件等等收尾工作。

接下来编译工程,打包VSIX就完成了,目前实现的主要Feature:

1、当在代码编辑器中选择一段文字,并将鼠标移到文字区域时,QuickToolbar会以半透明的方式“浮”文字的旁边。 2、当鼠标移到QuickToolbar区域,QuickToolbar会变成不透明,其上的按钮会响应鼠标动作。 3、目前支持的操作有:

  • 剪切(Cut)
  • 复制(Copy)
  • 粘贴(Paste)
  • 删除(Delete)
  • 减小缩进(Decrease Indent)
  • 增加缩进(Increase Indent)
  • 注释代码(Comment)
  • 取消注释(Uncomment)
  • 等等

VSIX和源代码下载以及安装方法: [VS2010扩展]浮动工具栏(http://gcdn.grapecity.com/showtopic-345.html)

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏葡萄城控件技术团队

七天学会ASP.NET MVC (五)——Layout页面使用和用户角色管理

系列文章 七天学会ASP.NET MVC (一)——深入理解ASP.NET MVC 七天学会ASP.NET MVC (二)——ASP.NET MVC 数据传递 ...

35280
来自专栏友弟技术工作室

GoLang实现google authenticator的CLI工具

两步认证在很多验证中都要使用。如果在手机客户端上,如果使用电脑,每次都要拿出手机,手动输入。还要担心会过时。效率不是很高。

18030
来自专栏林德熙的博客

wpf DoEvents 用法原理存在的坑推荐方法

如果在执行一段卡UI的代码,这时如何让UI响应。如果存在代码需要获得依赖属性,那么代码就需要在UI线程执行,但是这时就会卡UI,为了让UI响应,所以就需要使用D...

81310
来自专栏更流畅、简洁的软件开发方式

用接口实现事件的一种方法,只是玩玩。

  前一阵子,firelong说,应该用接口实现事件,而不应该用委托。我就希望他能给出一个用接口实现事件的方法,我是一直等呀,等到了现在也没有看到。   昨天又...

25680
来自专栏hotqin888的专栏

用beego进行onlyoffice document server的二次开发

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/hotqin888/article/det...

22920
来自专栏酷玩时刻

微信公众号开发之自定义菜单

在Jfinal-weixin中有封装菜单的创建、查询、删除、以及个性化菜单的创建、查询、删除、测试个性化菜单匹配结果

15020
来自专栏跟着阿笨一起玩NET

如何在控件的设计时得到窗体设计器中的所有控件

本文转载:http://www.cnblogs.com/Ricky81317/archive/2007/01/04/611942.html

10410
来自专栏林德熙的博客

WPF 修改图片颜色

在 WPF 可以使用很多图片处理的方法,本文告诉大家的是一个图片处理,可以把处理的图片保存在文件。

43810
来自专栏前端布道

前端开发必备之Emmet

·介绍 Emmet (前身为 Zen Coding) 是一个能大幅度提高前端开发效率的一个工具。 基本上,大多数的文本编辑器都会允许你存储和重用一些代码块,我们...

33440
来自专栏林德熙的博客

win10 uwp 萤火虫效果 安装 win2d创建界面后台的方法核心代码

本文在Nukepayload2指导下,使用他的思想用C#写出来。 本文告诉大家,如何使用 win2d 做出萤火虫效果。

14710

扫码关注云+社区

领取腾讯云代金券