Component Port
The letter killeth, but the spirit giveth life.
随笔- 50  文章- 0  评论- 123 
博客园  社区  首页  新随笔    管理  订阅 订阅
2010年6月13日
VS2010 Extension实践(3)——实现自定义配置

在之前的两篇曾提到通过VSSDK(MSDN也叫VSX)来拓宽思路,实现一些MEF Extension所不能做到的功能,比如获取IVsUIShell服务来执行Command等等,这里我给各位看官展示如何通过VSX提供自定义配置到IDE里面。

首先创建一个Package工程,找到里面的XX_Package.cs,要提供自定义配置到IDE,需要在这里通过ProviderProfile和ProviderOptionPage告诉Package两个重要信息:此Package有配置信息(Profiler)以及对应该配置信息的界面,这里我从我的GotoDef extension工程里截了一张图:

ProvideProfiler/ProvideOptionPage attributes usage, click to enlarge

其中ProvideProfile告诉Package提供的Profiler的相关信息:关联的提供该Profiler的类型、分类名称、页面名称、资源ID等等,VS在需要时会把保存的信息(默认在注册表里)读取并反序列化成关联的类型的对象,在关闭Option对话框或者确认应用配置时,会把配置信息对象序列化保存(默认在注册表)。

另一个ProvideOptionPage来指定配置信息对象和界面,它是从DialogPage派生,需要注意的是需要为它提供Guid和ClassInterface类型;默认情况下,显示该配置对象使用PropertyGrid,当然,可以通过override Window属性来自定义自己的UI,比如GoToDef中的配置UI,如下图:

GoToDefOptPage

 

完成以后在VS Extension工程中引用这个Package并添加到VSIX输出中,这样就可以使用配置了:

Use_GoToDef_Opt

Use_GoToDef_Opt2

至此,为VS Extension提供自定义配置的工作就完成了,具体效果可以参考我的上一篇帖子:

http://www.cnblogs.com/winkingzhang/archive/2010/02/26/1673995.html
Visual Studio .NET 2010 Options

posted @ 2010-06-13 12:33 winkingzhang 阅读(1385) 评论(0) 编辑
2010年2月26日
[VS2010 Extension]PowerExtension.GoToDefinition

自己实现了一个Visual Studio.NET 2010扩展,使用MS-PL协议发布。

 

功能:
模仿Word上对链接的处理,当按住设置的Modifier键,鼠标点击代码中的标识词就可以快速切换到该标识词的定义代码,即Visual Studio中的GoToDefinition功能(F12)。

下载链接:http://files.cnblogs.com/winkingzhang/PowerExtension.GoToDefinition.zip


使用截图
Snapshot
配置截图
Visual Studio .NET 2010 Beta2 Options

 

如果你发现bug,欢迎跟帖提出,谢谢!

 

运行环境:
Visual Studio .NET 2010 Ultimate RTM
Visual Studio .NET 2010 Premium RTM
Visual Studio .NET 2010 Professional RTM

 

发布历史:

V1.2

支持Visual Studio 2010 RTM

V1.1
修改默认的Modifier键成Alt;
增加自定义设置功能,通过Options对话框来修改自己喜欢的Modifier;

V1.0
实现Ctrl+MouseClick浏览代码定义;
实现按住Ctrl键后为可导航的标识词添加下划线;

posted @ 2010-02-26 10:33 winkingzhang 阅读(369) 评论(2) 编辑
2010年2月4日
VS2010 Extension实践(2)

在上一篇(VS2010 Extension实践)里,主要展示了如何使用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 ?
(
uint)VSConstants.VSStd2KCmdID.COMMENT_BLOCK :
(
uint)VSConstants.VSStd2KCmdID.UNCOMMENT_BLOCK;
8 object arg = null;
9 shell.PostExecCommand(ref std2k, cmdId, 0, ref arg);
10 }
11 }
至此,我们通过VSSDK提供的能力,顺利的挖掘出VS2010 Extension的部分宝藏,你是不是也有点心动,要自己去挖掘一点呢?


PS:

本文所讲解内容是根据我的练习之作而进行的,如果需要源代码,请自行到GCDN论坛下载,代码和VSIX安装程序均匀更新:

[VS2010扩展]浮动工具栏(http://gcdn.grapecity.com/showtopic-345.html

posted @ 2010-02-04 22:01 winkingzhang 阅读(1624) 评论(2) 编辑
2010年1月26日
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事件处理要记得取消所有挂这个事件等等收尾工作。

 

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

接下来编译工程,打包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)

posted @ 2010-01-26 22:08 winkingzhang 阅读(1999) 评论(4) 编辑
2010年1月12日
如何通过反射调用带有ref或者out的参数的方法[迁移]

原帖放在GCDN上,由于GCDN做了整合调整,现在关注产品交流等原因GCDN Blog关闭了,只好把一些有用点的搬过来了。

2009年8月13日 12:29 by winking

写这篇博客,原起今天CyljXu问我一个问题:如何通过反射调用带有ref或者out的参数的方法?想着可能其他人也会遇到这个问题,权且记录下来,以备后行者搜索到。

这个在MSDN上有解释,参考 MethodBase.Invoke方法 。

public Object Invoke(
Object obj,
Object[] parameters
)

 

Visual C++
public
: virtual Object^ Invoke( Object^ obj, array 
J#
public
final Object Invoke( Object obj, Object[] parameters )
JScript
public
final
function
Invoke( obj : Object, parameters : Object[] ) : Object

参数

obj 类型:System.Object

对其调用方法或构造函数的对象。如果方法是静态的,则忽略此参数。如果构造函数是静态的,则此参数必须为 null 引用(在 Visual Basic 中为 Nothing ) 或定义该构造函数的类的实例。

parameters 类型: System.Object[]

调用的方法或构造函数的参数列表。这是一个对象数组,这些对象与要调用的方法或构造函数的参数具有相同的数量、顺序和类型。如果没有任何参数,则 parameters 应为 null 引用(在 Visual Basic 中为 Nothing ) 。

如果此实例所表示的方法或构造函数采用 ref 参数(在 Visual Basic 中为 ByRef ),使用此函数调用该方法或构造函数时, 该参数不需要任何特殊属性 。如果数组中的对象未用值来显式初始化,则该对象将包含该对象类型的默认值。对于引用类型的元素,该值为 null 引用(在 Visual Basic 中为 Nothing ) 。对于值类型的元素,该值为 0、0.0 或 false ,具体取决于特定的元素类型。

那么该如何调用并处理传值呢?请看如下示例:

1 class Program
2 {
3 static void Main(string[] args)
4 {
5 string content = "main"; //#1 variable
6   MethodInfo testMethod = typeof(Program).GetMethod("TestMethod",
7 BindingFlags.Static | BindingFlags.NonPublic);
8 if (testMethod != null)
9 {
10 // Following way can not take content back.
11 // -------------------------------------
12   testMethod.Invoke(null, new object[] { content /* #1 variable */ });
13 Console.WriteLine(content); // #1 variable, Output is: main
14 // -------------------------------------
15  
16
17 object[] invokeArgs = new object[] { content /* #1 variable */ };
18 testMethod.Invoke(null, invokeArgs);
19 content = (string)invokeArgs[0]; // #2 variable, bypass from invoke, set to content.
20   Console.WriteLine(content); // #2 variable, Output is: test
21   }
22 }
23
24 static void TestMethod(ref string arg)
25 {
26 arg = "test"; // #2 variable, wanna bypass to main process.
27   }
28 }
posted @ 2010-01-12 14:00 winkingzhang 阅读(1919) 评论(13) 编辑
Win7硬盘安装和移动硬盘访问出错的修复办法[迁移]

原帖放在GCDN上,由于GCDN做了整合调整,现在关注产品交流等原因GCDN Blog关闭了,只好把一些有用点的搬过来了。

2009年8月17日 17:10 by winking

前不久终于拿到了Windows 7 RTM,迫不及待的就想在物理机器上安装,但是没借到光盘,只好思量如何硬盘安装了。

几经尝试,得出安装方法如下:

1、使用虚拟光驱软件(如Daemon Tools)加载ISO,将其中内容全部拷贝到非C:\的地方(例如D:\Win7Setup);

2、这一步根据系统不同略有一些不同:
a)Windows XP/2003:
(1)拷贝bootmgr文件,boot目录到C:\下,然后在C:\下加一个名为 Sources 的目录,从拷贝sources\boot.wim到刚才建立的 Sources 目录;
(2)打开CMD,执行" C:\boot\bootsect.exe /nt60 C:\ ",然后重启;
(3)等待启动后,进入 “开始安装界面”,点左下角选择“修复计算机”( repair my computer

3、选择自定义安装(Custom),然后格式化C:\ ,完成剩下安装,经历若干次重启就可以开始完全干净的Windows 7之旅了。

 

-------------------------------我是无敌分割线-----------------------------------

刚刚安装完成Windows 7的安装,想起来把之前备份在移动硬盘上的资料恢复回来,于是麻利的把移动硬盘差了上去,看到提示是否进行错误检查,心想之前用的好好的应该没有问题吧,就直接取消了,打开我的电脑,直奔备份资料的分区而去,双击,“当……”,提示“磁盘没有格式化,是否格式化?”,呃,这个……有点……,于是拔了,换到 XP上试了一下,正常访问;貌似很神奇的,拿着移动硬盘回到Win7上又提示“磁盘没有格式化,是否格式化?”了!^_^`!。

于是查了一下资料,发现Window XP和Windows 7上的NTFS是不一样的,具体参考各大搜索引擎。

回到问题上,备份访问不了可是很着急的啊,突然想起来,移动硬盘插入的时候提示是否进行磁盘错误检查了,那不就是CHKDSK嘛,试试吧,以管理员身份打开命令行,直接"CHKDSK K:",等待n久,结果还是没有好,只好看看CHKDSK还能干什么(你可以通过“CHKDSK /?”来看到),发现有个选项/F,描述很简单,但是就是我想要的——“Fixes errors on the disk.”,接着执行命令行“ CHKDSK /F K: ”,又是等待n久,这次显示有些不一样,多了不少“XX Index Error”之类的提示,心想这次貌似可以了,结果打开我的电脑,直接双击K盘,提示“access denied”,右键查看属性,居然可用空间和已用空间都是0,神奇的Windows 7!此时我开着CMD,很郁闷,就直接按UP键,随意调了个命令就执行了,结果刷的一下显示了n长的目录列表,看着很熟悉……呃,原来就是我备份的文件呀,哦!原来已经修复好了,不过权限分配有点问题(要不怎么提示“access denied”呢!),于是查看属性的权限页,发现确实没有EveryOne的读写权限(EveryOne完全控制是移动设备的默认基本属性)了,只有寥寥几个特殊帐户的配置,而且没有任何读写的权限,原来问题在这里——修复就很简单了, 给目录加上EveryOne的完全控制权限 就可以了。

 

后记:

在TechNet已经有人在讨论这个Window 7分区的问题,详细参考 Windows 7 NTFS vs. Windows XP NTFS ,结论是:
Although XP found the drive clean, Window 7 fails to recognize a SID (Security IDentifiers) from XP. There is nothing wrong, per se, with your drive; Windows 7 just throws a fit with your XP SIDs.

posted @ 2010-01-12 13:48 winkingzhang 阅读(1917) 评论(0) 编辑
2009年6月14日
zt. Windows Mobile开发文章收藏
摘要: 入门或理论研究系列文章 智能手机 手机词汇 研发手机基本流程 我理解的Windows moblie J2ME,CompactFramework,c++,我该如何取舍 Windows Mobile Jump Start Guide 从0开始Windows Mobile 开发 3G 手机流媒体应用,看上去很美 基于rtsp的手机视频点播实现和研究 手机流媒体UI开发WINCE应用的UI实现方案 &md...阅读全文
posted @ 2009-06-14 09:37 winkingzhang 阅读(530) 评论(0) 编辑
2009年1月15日
[WPF]在Style中设置ToolTip的问题分析
摘要: 刚才开到智者千虑发的【WPF】在Style中设置ToolTip的问题的博文,虽然最终给了一个暂时解决问题的方案,但是没有分析和解释其中的问题,正与他所说:但至于为什么不能直接在Setter.Value中放置TextBlock还是一个未解之谜。 趁着中午间隙,跟踪了一下,这里我将带给你完整的分析。 阅读全文
posted @ 2009-01-15 16:49 winkingzhang 阅读(1318) 评论(2) 编辑
2009年1月13日
[WPF]RadioButton在Group的Header区部分不响应鼠标选择的bug分析
摘要: 昨晚看到南柯之石的WPF BUG之四:点击RadioButton的空白没有反应,就做了简单的验证,之后发表了一些分析和看法,但是那个分析不够准确和充分,导致了对别人的想法一些误导。在此表示歉意。这里我会从头做分析。阅读全文
posted @ 2009-01-13 13:54 winkingzhang 阅读(1534) 评论(2) 编辑
2008年12月1日
WPF模式思考 (zt)
摘要: Xaml的出现使得Win下非常有效的MVC变得复杂了很多很多,而WPF的发布使得Web程序和Win程序的鸿沟渐渐填平,对于模式的思考也渐渐浮出来:是使用复杂化的MVC,还是微软提出的MVP,抑或其他的模式。阅读全文
posted @ 2008-12-01 11:59 winkingzhang 阅读(751) 评论(2) 编辑
仅列出标题  下一页
Copyright ©2012 winkingzhang