zoukankan      html  css  js  c++  java
  • VS2010 Extension实践

    最近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 }
    90  

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

    接下来编译工程,打包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)
  • 相关阅读:
    在浏览器中浏览git上项目目录结构
    部署elasticsearch(三节点)集群+filebeat+kibana
    谷歌浏览器安装Elasticsearch-head 插件
    Logstash配置文件修改自动加载和指定目录进行启动
    使用Dbvisualizer 连接 Elasticsearch
    Elasticsearch常见用法-分布式集群
    Elasticsearch常见用法-入门
    Elastic Stack 7.5.0白金版永不过期
    配置 Nginx 反向代理 WebSocket
    ES7.3.0配置
  • 原文地址:https://www.cnblogs.com/winkingzhang/p/1657059.html
Copyright © 2011-2022 走看看