详解VisualStudio2010Extension的应用

对于即将发布正式版的Visual Studio 2010,有一个Visual Studio 2010 Extension功能。平时大家关注Visual Studio 2010 Extension不多,希望通过本文能让大家更好的了解。

创新互联建站专业为企业提供新丰网站建设、新丰做网站、新丰网站设计、新丰网站制作等企业网站建设、网页设计与制作、新丰企业网站模板建站服务,10余年新丰做网站经验,不只是建网站,更提供有价值的思路和整体网络服务。

最近Visual Studio 2010 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. }  

这样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;  

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

 
 
 
 
  1. this._adornmentLayer = 
  2. this._textView.GetAdornmentLayer("QuickToolbarAdornmentLayer"); 

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

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

由于我们要通过工具栏操作代码,所以需要通过MEF导入IEditorOperationsFactoryService:这样就可以在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(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)
  • 等等

上面主要展示了如何使用MEF扩展VS2010,来扩展编辑控制和展现自己的UI;在实现QuickToolbar的时候,发现MEF仅仅提供了很基本的编辑控制,如果需要高级的操作,比如注释选择的代码,就捉襟见肘,很是麻烦。

我将展示如何深入挖掘VS2010 Extension,使它成为锋利的军刀,而不是绣花枕头。鉴于此,这里就从上面提到了的Feature——注释和取消注释选择的代码来剖析,希望可以为大家拓宽思路,更好的利用VS2010。

首先回顾一下上篇中的实现,当时是基于TextViewLine做注释代码的,这里有两个潜在问题:其一,TextViewLine,顾名思义,是“可视区域”的行,所以如果选择超出可视区域,超出的部分就没有注释掉;其二,当选择的结束位置在行的结尾时,无法实现IDE注释代码后保持Caret在选择结尾而不跳到下一行的行为,当尝试自己重新选择并移动Caret就会收到ITextSpanshot无效的异常。

上面提到了VS2010 Extension对编辑器的编辑行为的控制能力仅仅提供了通用的,比如Cut/Copy/Paste等等,而其他的诸如注释/取消注释代码,添加、删除、导航到Bookmark等程序员常用功能没有暴露出来,具体可以参考IEditorOperations Interface(http://msdn.microsoft.com/en-us/library/microsoft.visualstudio.text.operations.ieditoroperations_methods%28VS.100%29.aspx),这里的所有Member表达了其所支持的编辑操作。总之,这条路只有这么几个目的地。

那么,还有其他方法吗?貌似走到了死胡同了,但是当我们使用IDE时候,却是可以很容易的通过Edit菜单找到所有的功能的,问题是,它们要怎样才能为我所用呢?

我首先想到的是在VSSDK中找找,结果一个名字看起来很顺眼的接口撞到眼里,它就是IVsUIShell Interface(http://msdn.microsoft.com/en-us/library/microsoft.visualstudio.shell.interop.ivsuishell%28VS.100%29.aspx),MSDN上市这么说的:

This interface provides access to basic windowing functionality, including access to and creation of tool windows and document windows. provided by the environment.

也就是说这是一个由IDE提供的全局的Service,可以创建、访问工具窗口和编辑窗口。浏览一下这个所有Member,发现了一个叫IVsUIShell.PostExecCommand(...)(http://msdn.microsoft.com/en-us/library/microsoft.visualstudio.shell.interop.ivsuishell.postexeccommand%28VS.100%29.aspx)的方法,MSDN描述说通过它可以异步执行Command,那么,只要找到注释代码的Command,在通过这个接口就可以实现VS IDE一样的注释代码的Feature了。酷毙了,就是它,当怎么得到它呢?现在请留心MSDN上的解释,就是上面我使用红色粗体表示出来的部分——这个由IDE提供的全局的Service,那么可以通过Package.GetGlobalService(...)(http://msdn.microsoft.com/en-us/library/microsoft.visualstudio.shell.package.getglobalservice%28VS.100%29.aspx)来获取:

IVsUIShell shell = Package.GetGlobalService(typeof(IVsUIShell)) as IVsUIShell;

接下来是找到自己需要Command,然后PostExecCommand就搞定了;而VS提供的Command有两部分组成:Guid和CommandID,这个大部分都在VSConstants Class(http://msdn.microsoft.com/en-us/library/microsoft.visualstudio.vsconstants%28VS.100%29.aspx)里面,以注释代码为例,其Guid是:VsConstants.VSStd2k,而CommandID是VSConstants.VSStd2kCmdID.COMMENTBLOCK。下面是我包装的注释和取消注释的代码片段:

 
 
 
 
  1.  public static void ProcessComments(bool comment)  
  2.  {  
  3.  IVsUIShell shell = Package.GetGlobalService(typeof(IVsUIShell)) as IVsUIShell;  
  4.  if (shell != null)  
  5.  {  
  6.  Guid std2k = VSConstants.VSStd2K;  
  7.  uint cmdId = comment ?   
  8. (uint)VSConstants.VSStd2KCmdID.COMMENT_BLOCK :  
  9. (uint)VSConstants.VSStd2KCmdID.UNCOMMENT_BLOCK;  
  10.  object arg = null;  
  11.  shell.PostExecCommand(ref std2k, cmdId, 0, ref arg);  
  12.  }  
  13.  } 

至此,我们通过VSSDK提供的能力,顺利的挖掘出VS2010 Extension的部分宝藏,你是不是也有点心动,要自己去挖掘一点呢?

网站栏目:详解VisualStudio2010Extension的应用
链接URL:http://www.shufengxianlan.com/qtweb/news14/151614.html

网站建设、网络推广公司-创新互联,是专注品牌与效果的网站制作,网络营销seo公司;服务项目有等

广告

声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 创新互联