找回密码
 立即注册

QQ登录

只需一步,快速开始

thrall

超级版主

14

主题

174

帖子

2072

积分

超级版主

Rank: 8Rank: 8

积分
2072

活字格认证微信认证勋章

thrall
超级版主   /  发表于:2013-5-7 10:18  /   查看:5713  /  回复:0
最近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对象:
  1. [TextViewRole("DOCUMENT")]
  2. [Export(typeof(IWpfTextViewCreationListener))]
  3. [ContentType("text")]
  4. internal sealed class PETextViewCreationListener : IWpfTextViewCreationListener   
  5. {
  6.         void IWpfTextViewCreationListener.TextViewCreated(IWpfTextView textView)
  7.         {
  8.             //...
  9.         }
  10. }
复制代码


这样VS就会在合适的时候调用IWpfTextViewCreationListener.TextViewCreated方法来通知文字编辑的状态改变。

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

  1. [Name("QuickToolbarAdornmentLayer")]
  2.         [Order(After = "Text")]
  3.         [Export(typeof(AdornmentLayerDefinition))]
  4.         public AdornmentLayerDefinition QuickToolbarLayerDefinition
  5.         {
  6.             get;
  7.             set;
  8.         }
复制代码


这里的Name Attribute很重要,以后的代码中要获取我们的AdornmentLayer就得靠它了:

  1. this._adornmentLayer = this._textView.GetAdornmentLayer("QuickToolbarAdornmentLayer");
复制代码


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

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

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

  1. [Import]
  2.         internal IEditorOperationsFactoryService EditorOperationsFactoryService
  3.         {
  4.             get;
  5.             set;
  6.         }
复制代码


这样就可以在IWpfTextViewCreationListener.TextViewCreated中通过IEditorOperationsFactoryService.GetEditorOperations(ITextView)来获得IEditorOperations,有了它,就可以方便快捷的编辑代码了。

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

  1. 1                 private void MayBeAdornmentShowCondition()
  2. 2                 {
  3. 3                     if (!this._textView.Selection.IsEmpty)
  4. 4                     {
  5. 5                         SnapshotPoint startPos = this._textView.Selection.Start.Position;
  6. 6                         SnapshotPoint endPos = this._textView.Selection.End.Position;
  7. 7                         IWpfTextViewLine textViewLineContainingBufferPosition = this._textView.GetTextViewLineContainingBufferPosition(startPos);
  8. 8                         TextBounds characterBounds = textViewLineContainingBufferPosition.GetCharacterBounds(startPos);
  9. 9                         TextBounds bounds2 = this._textView.GetTextViewLineContainingBufferPosition(endPos).GetCharacterBounds(endPos);
  10. 10                         if (this._fromMouseHover)
  11. 11                         {
  12. 12                             this._mustHaveAdornmentDisplayed = true;
  13. 13                         }
  14. 14                         else
  15. 15                         {
  16. 16                             PELeftButtonMouseProcessor property = null;
  17. 17                             try
  18. 18                             {
  19. 19                                 property = this._textView.Properties.GetProperty<PELeftButtonMouseProcessor>(typeof(PELeftButtonMouseProcessor));
  20. 20                             }
  21. 21                             catch
  22. 22                             {
  23. 23                             }
  24. 24                             this._mustHaveAdornmentDisplayed = (property != null)
  25. 25                                 &amp;&amp; (property.IsLeftButtonDown
  26. 26                                 || ((DateTime.Now - property.LastLeftButtonDownTime).TotalMilliseconds < 400.0));
  27. 27                         }
  28. 28                         if (this._mustHaveAdornmentDisplayed)
  29. 29                         {
  30. 30                             TextBounds selectionBounds = !this._textView.Selection.IsReversed ? bounds2 : characterBounds;
  31. 31                             int offset = 7;
  32. 32                             double top = selectionBounds.Top + (!this._textView.Selection.IsReversed ? (offset + textViewLineContainingBufferPosition.Height) : (-offset - this._adornmentUI.ActualHeight));
  33. 33                             if (top < 0.0)
  34. 34                             {
  35. 35                                 top = 0.0;
  36. 36                             }
  37. 37                             double left = characterBounds.Left + ((bounds2.Left - characterBounds.Left) / 2.0);
  38. 38                             if ((left + this._adornmentUI.ActualWidth) > this._textView.ViewportWidth)
  39. 39                             {
  40. 40                                 left = this._textView.ViewportWidth - this._adornmentUI.ActualWidth;
  41. 41                             }
  42. 42                             Canvas.SetTop(this._adornmentUI, top);
  43. 43                             Canvas.SetLeft(this._adornmentUI, left);
  44. 44                             long chars = 0L;
  45. 45                             try
  46. 46                             {
  47. 47                                 chars = this._textView.Selection.SelectedSpans[0].Span.Length;
  48. 48                             }
  49. 49                             catch
  50. 50                             {
  51. 51                             }
  52. 52                             this._adornmentUI.SetStatus(chars);
  53. 53                             this.RenderSelectionPopup();
  54. 54                         }
  55. 55                     }
  56. 56                     else
  57. 57                     {
  58. 58                         this._mustHaveAdornmentDisplayed = false;
  59. 59                         this._adornmentLayer.RemoveAdornmentsByTag(this._adornmentTag);
  60. 60                     }
  61. 61                 }
  62. 62
  63. 63                 private void RenderSelectionPopup()
  64. 64                 {
  65. 65                     if (this._mustHaveAdornmentDisplayed)
  66. 66                     {
  67. 67                         IAdornmentLayerElement element = null;
  68. 68                         try
  69. 69                         {
  70. 70                             element = this._adornmentLayer.Elements.First<IAdornmentLayerElement>(
  71. 71                                 (IAdornmentLayerElement ile) => ile.Tag.ToString() == this._adornmentTag);
  72. 72                         }
  73. 73                         catch (InvalidOperationException)
  74. 74                         {
  75. 75                         }
  76. 76                         if (element == null)
  77. 77                         {
  78. 78                             this._adornmentLayer.AddAdornment(this._textView.Selection.SelectedSpans[0], this._adornmentTag, this._adornmentUI);
  79. 79                         }
  80. 80                         this._timer.Stop();
  81. 81                         this._timer.Start();
  82. 82                     }
  83. 83                 }
  84. 84
  85. 85                 private void selection_SelectionChanged(object sender, EventArgs e)
  86. 86                 {
  87. 87                     this._fromMouseHover = false;
  88. 88                     this.MayBeAdornmentShowCondition();
  89. 89                 }
复制代码


然后要注意的是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)

0 个回复

您需要登录后才可以回帖 登录 | 立即注册
返回顶部