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事件了,上面提到会挂这个事件就是为这里用的。

ContractedBlock.gif ExpandedBlockStart.gif 代码
 
   
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事件处理要记得取消所有挂这个事件等等收尾工作。

 

image.gif semi.png(12.70 K)
2010-1-25 16:42:05
image.gif toolbar.png(15.64 K)
2010-1-25 16:42:05

接下来编译工程,打包VSIX就完成了,目前实现的主要Feature:
1、当在代码编辑器中选择一段文字,并将鼠标移到文字区域时,QuickToolbar会以半透明的方式“浮”文字的旁边。
 attachment.aspx?attachmentid=53
2、当鼠标移到QuickToolbar区域,QuickToolbar会变成不透明,其上的按钮会响应鼠标动作。
 attachment.aspx?attachmentid=54
3、目前支持的操作有:

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

 

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

转载于:https://www.cnblogs.com/winkingzhang/archive/2010/01/26/1657059.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值