最近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和源代码下载以及安装方法在GCDN论坛: [VS2010扩展]浮动工具栏(http://gcdn.grapecity.com/showtopic-345.html)
分享到:
相关推荐
这是一个通用的 hello world 实践。 可以从这里开始最简单的 Python C 扩展示例。 01-嘿人 这是一种从 Python 获取参数的 C 扩展实践。 heyman 函数将回显传递的名称和编号。 02-添加 它是一个加法函数,它不仅会...
概述本次会议向与会者介绍了一个端对端流程,以使用SAP Extension Suite中的最佳实践来构建扩展。 该研讨会将指导您逐步完成使用SAP Cloud应用程序编程模型(CAP)创建新的数据模型和服务集成在SAP API Business Hub...
适用于Chrome和Firefox的React Extension样板 仍在开发中!... 使用ESLint,Jest,React-StoryBook,Webpack等实现所有最佳Javascript实践。 资料来源: : 安装 :chequered_flag: 安装此样板
前几天稍微看了一下Ratchet,并且实践了一下它官方例子。所以现在就将实践的过程记录下来。 在具体实践之前先将Ratchet是什么东东,要先说明一下。以下的英文是从官方copy过来的 Ratchet is a loosely coupled ...
onepassword-app-extension-xamarin Xamarin.iOS与AgileBits 1Password应用程序扩展库的绑定 用法 下载并将其引用添加到您的项目中。 创建一个按钮并将其添加到您的密码UITextField中: if ( ...
通过准确的数据和快速响应时间,您的实践将消除与传统购买技术相关的常见错误和浪费努力。重要说明:需要订阅方法采购。如果您有任何问题或建议,请访问https://support.methodusa.com以获取有用的资源。想要提高你...
chrome-extension-hands-on 关于 请参阅。 执照 麻省理工学院: :
# go to the extension examples folder cd jupyterlab-extension-examples # create a new environment conda env create # activate the environment conda activate jupyterlab-extension-examples # go to the ...
生物识别(用于指纹或面部识别的简便易用的最佳实践) 警报(修复全局警报) SpeechToText(设置用于语音识别的计时器) 权限(使用简单的回调轻松获得权限) 位置(通过回调获取位置,无需担心权限代码) ...
随着教程程序具有易于掌握的内容,深入的说明,更新的版本和实用的功能,可以保证该单一的教程网站将使应聘者获得完整,逐步,系统化和基于实践的知识。支持多个示例。 我们很高兴为所有PHP学习者提供帮助,并始终...
junit-extension 背景 原生的Junit无法满足我们在自动化测试实践过程中的碰到一些需求,比如 管理人员希望统计测试组每个成员开发的用例数目, 要是每个用例都能够有注释 在本地调试测试用例时,测试工程师希望只运行...
适用于Chrome的RockTech Extension 通过在需求点为用户提供业务洞察力,关键笔划指导和最佳实践来提高Salesforce的采用率。根据客户的配置,RockTech:trade_mark:根据用户的角色和流程提供用户需要了解的信息。 支持...
SkySmart助手如果您曾经做过SkySmart测试或家庭作业,那么您就会知道它们在所有现代Web设计实践中有多糟糕: 防止选择文字禁止打开DevTools 在页面上阻止搜索此扩展将帮助您修复SkySmart的所有缺陷。 如“安装”部分...
doctor-jones-extension 链接 · 相关项目 · · More to be developed... 琼斯医生 :pill: 一个能够美化网页中文排版(包括中英文混排)的扩展 特性 遵循 和其他中文排版最佳实践,格式化你正在浏览的页面 ...
语言:English (United States...通过在需要时为用户提供业务洞察力,按键指导和最佳实践,从而提高Salesforce的采用率。 RockTech:trade_mark:根据客户的配置量身定制,可根据用户的角色和流程提供用户需要了解的内容。
:ram: @ testing-library / react-hooks -React钩子鼓励鼓励良好测试实践的测试实用程序 :dog_face: 赫斯基-轻松使用git钩子 :high_voltage: 自动安装项目的对等依赖项- :card_index_dividers: 基本模块结构 :...
这是一个启动文件夹,用于创建带有 1 个弹出页面的 chrome 扩展。
进一步开发来自作者这个扩展是为了好玩而创建的,为了满足他们在实践中的卑鄙、粗俗和无用的完美主义,我知道这个问题可以以更少和更少的时间得到最佳解决。 我试图创造最方便、快速和稳定的机制来解决他们练习任务...
特点除了相关资源,样本资料,参考图片,一般最佳实践等,我们还将主要研究以下关键部分:★URL更新的URL(不包括默认的字母数字字符串)可以带来更好的搜索结果。 连同样本和参考图像,查看技巧和一般最佳实践。 ...
同时我们也在 Rust 社区进行了 Envoy WASM extension 及 eBPF extension 等场景探索。 2022 年,Sentinel 品牌升级为流量治理,领域涵盖流量路由/调度、流量染色、流控降级、过载保护/实例摘除等;同时