office开发之使用窗口

 

一、             使用窗口

 1  使用WinForm窗口

VS.NET中显示WinForm窗口非常容易,和平常编写WinForm程序没什么两样,步骤如下:

l          在项目里添加一个WinForm窗体

l          修改WinForm窗体的构造函数

VS环境的根对象DTE对象传入,以便在WinForm中可以操纵开发环境

       publicclass MyForm : System.Windows.Forms.Form

       {      

private EnvDTE.DTE applicationObject;

       public MyForm(EnvDTE.DTE applicationObject)

       {

           InitializeComponent();

           this.applicationObject = applicationObject;

          

       }

 

l          Connect文件的Exec函数里生成并显示WinForm窗体。

            MyForm form =new MyForm(this.applicationObject.DTE);

            form.ShowDialog();

注意:这里的this.applicationObject_DTE接口指针,它的一个成员DTE成员才是DTE对象,不能直接用类型转换如(DTE) this.applicationObject



图-VS集成环境里显WinForm窗体 

 

2  使用工具窗口

VS.NET的工具窗口指的是类似“解决方案资源管理器”,“类视图”,“工具箱”这样停靠在上下左右侧边的窗口。而如代码编辑窗口这样的窗口,需要用VSIP进行开发,外接程序插件是没有办法开发这类窗口的。

根据MSDN里的资料,如果要开发侧边工具窗口,是件非常繁琐的事情。因为VS.NET是基于COM开发的,所以开发出来的侧边工具窗口也需要实现一系列接口,也就是说,不能直接使用.NET程序集。幸而已经有人做了这件事情,开发了一个将.NET用户控件包装成COM组件的容器VSUserControlHostLib,使得我们只需要开发出.NET用户控件,就可以将其嵌入到VS集成环境里了

开发步骤:

1   生成Addin项目

2   在项目中添加VSUserControlHost.dll引用

3   Connect.cs文件的OnConnection方法中添加显示窗口的代码

下面是代码示例:(添加在OnConnect方法中)

 

//GUID串可以用VS开发环境里菜单命令“工具à创建GUID”弹出的对话框创建

        string guidstr = "{65FADCBF-63D2-448b-8A4B-393D7E751345}";

        object objTemp =null;

        VSUserControlHostLib.IVSUserControlHostCtl objControl =null;

        //create the 'Explorer' tool window

        /*

            [C#]

            返回一个 Window对象

            public Window CreateToolWindow(

            AddIn AddInInst, //必选项。其生存期决定工具窗口生存期的 AddIn对象

            string ProgID,       //必选项。Document对象或 ActiveX 控件的编程 ID

            string Caption,  //新工具窗口的标题

            string GuidPosition,  //新工具窗口的唯一标识符,可用作 Window.Item的索引

            ref object DocObj//工具窗口中要承载的 Document对象或控件

            );

        */

        //这里先生成容器窗口,返回的控件对象在objTemp

        windowExplorer = applicationObject.Windows.CreateToolWindow(

addInInstance,

"VSUserControlHost.VSUserControlHostCtl",

"菜单浏览器",

guidstr,

ref objTemp);

        //使用容器窗口时,必须在调用该容器控件前设置其为可见,否者将会不能正常显示

        windowExplorer.Visible =true;

        windowExplorer.IsFloating =false;

        //将返回的工具窗口转换为容器对象

        objControl = (VSUserControlHostLib.IVSUserControlHostCtl)objTemp;

        System.Reflection.Assembly asm = System.Reflection.Assembly.GetExecutingAssembly();

        //用容器对象包含用户控件,

        menuExplorer = (MenuExplore)objControl.HostUserControl(asm.Location,

"MenuBrowser.MenuExplore");

        //设置窗口的图标

//windowExplorer.SetTabPicture()

            //将DTE对象赋给窗口

menuExplorer.Application = applicationObject;

 

说明:

l          生成工具窗口:

以上代码先用CreateToolWindow函数生成工具窗口,工具窗口里承载的VSUserControlHost.VSUserControlHostCtl类型控件由objTemp对象返回

 

l          设置可见性:

将工具窗口设置为可见,非浮动

 

l          获取IVSUserControlHostCtl接口:

将返回的工具窗口中承载的控件对象objTemp转换为IVSUserControlHostCtl接口类型,并赋给objControl对象

 

l          加载用户控件:

objControlHostUserControl方法加载指定程序集的指定用户控件对象,上面代码中因为MenuBrowser.MenuExplore类是在插件项目的程序集里,所以用System.Reflection.Assembly.GetExecutingAssembly()方法获取当前程序集位置。如果用户控件是在其他程序集里,需要根据实际情况指定程序集位置

 

 

4   最后还应该在OnDisconnection方法里关闭窗口

if(windowExplorer!= null)

{

     windowExplorer.Visible = false;

}

 

                  下图就是笔者用来列举所有的系统菜单对象名称的一个插件,使用的就是工具窗口

 

图-2 VS集成环境中使用工具窗口 
 

一、             操纵VS开发环境

VS.NET自动化模型涉及的面太广,本文只针对一些专题加以说明。

1、   利用代码模型浏览代码

l          获取代码模型对象

//获取当前正活动的文档

    Document activeDocument = applicationObject.ActiveDocument;

    if(activeDocument !=null)

    {

        ProjectItem projectItem = activeDocument.ProjectItem;

        if(projectItem !=null)

        {

            FileCodeModel fileCodeModel = projectItem.FileCodeModel;

            if(fileCodeModel !=null)

            {

                CodeElements codeElements = fileCodeModel.CodeElements;

                if(codeElements !=null)

                {

                    foreach(CodeElement cein codeElements)

                    {

                        result.AddRange(getCodeElements(ce));

                    }

                }

            }

        }

}

说明:

上面的代码先从DTE对象(也即VS自动模型的根对象)获得当前正活动的文档对象

然后再根据文档对象获取和它关联的项目元素,这里的ProjectItem其实就是在解决方案资源管理器下面的项目文件夹对应的子项。可以是各种类型,如文件,文件夹等

再从项目元素获得关联的文件代码模型

根据文件代码模型获取其代码元素的集合CodeElementCollection,代码元素的父类为CodeElement,下面派生出许多的子类,代表具体的代码元素,分别有:

CodeNamespaceCodeClassCodeInterfaceCodeFunction

CodePropertyCodeVariableCodeDelegateCodeStructCodeEnum

代表着命名空间、类、接口、函数、属性、变量、委托、结构、枚举等类型的代码元素,某个CodeElement具体是何类型,可以根据CodeElement.vsCMElement枚举类型来判断,然后再显式转换成具体的子类即可

但是更进一步的代码元素,如函数体内的语句,好像还没有看到有方法检索。不过也可以利用一些其它的方法,比如CodeRush的程序集里面提供了一个StructuralParser程序集,用于C#的代码分析。如果谁有兴趣可以研究研究

 

l          根据具体类型检索代码元素(不再多做解释了):

        private ArrayList getCodeElements(CodeElement baseElement)

        {

            ArrayList result =new ArrayList();         

 

            switch(baseElement.Kind)

            {

                case vsCMElement.vsCMElementNamespace:

                    CodeNamespace cn = (CodeNamespace) baseElement;

                    foreach(CodeElement elementin cn.Members)

                    {

                        result.AddRange(getCodeElements(element));

                    }

                    break;

                case vsCMElement.vsCMElementClass:         

                    CodeClass cc = (CodeClass) baseElement;

                    foreach(CodeElement elementin cc.Members)

                    {

                        result.AddRange(getCodeElements(element));

                    }

                    break;

                case vsCMElement.vsCMElementInterface:

                    CodeInterface ci = (CodeInterface) baseElement;

                    foreach(CodeElement elementin ci.Members)

                    {

                        result.AddRange(getCodeElements(element));

                    }

                    break;

                case vsCMElement.vsCMElementFunction:

                    result.Add(baseElement);

                    break;

                case vsCMElement.vsCMElementProperty:

                    {

                        result.Add(baseElement);

                    }

                    break;

                case vsCMElement.vsCMElementEvent:

                    {

                        result.Add(baseElement);

                    }

                    break;

                case vsCMElement.vsCMElementDelegate:

                    {

                        result.Add(baseElement);

                    }

                    break;

                case vsCMElement.vsCMElementStruct:

                    {

                        result.Add(baseElement);

                        CodeStruct cs = (CodeStruct) baseElement;

                        foreach(CodeElement elementin cs.Members)

                        {

                            result.AddRange(getCodeElements(element));

                        }

                    }

                    break;

                case vsCMElement.vsCMElementEnum:

                    {

                        result.Add(baseElement);

                    }

                    break;

                case vsCMElement.vsCMElementAttribute:

                    result.Add(baseElement);

                    break;

                case vsCMElement.vsCMElementUsingStmt:

                    result.Add(baseElement);

                    break;

                case vsCMElement.vsCMElementVariable:

                    result.Add(baseElement);

                    break;

 

            }

            return result;

        }

 

2、   操纵解决方案及其项目文档

l          获取当前被选中的项目

下面代码演示了鼠标点击一个项目,或项目中的子项时,如何得到该项目对象

public Project GetSelectedProject()

{

   Project project =null;

   //从被选中对象中获取工程对象

   EnvDTE.SelectedItem item = Application.SelectedItems.Item(1);

 

   if(item.Project !=null)

   {//被选中的就是项目本生

       project = item.Project;

   }

   else

   {//被选中的是项目下的子项

       project = item.ProjectItem.ProjectItems.ContainingProject;

   }

   return project;

}

 

l          获取当前项目的所在目录

private string GetSelectedProjectPath()

{

   string path = "";

   //获取被选中的工程

   Project project = GetSelectedProject();

   if(project != null)

   {

       //全名包括*.csproj这样的文件命

       path = project.FullName;

   }

   //去掉工程的文件名

   path = Path.GetDirectoryName(path);

   return path;

}

 

l          将文件加入工程中

//获取被选中的工程

Project project = this.GetSelectedProject();

//将文件夹下的文件加入工程

project.ProjectItems.AddFromDirectory(sdir);

//将单个文件加入工程

project.ProjectItems.AddFromFile(nfile);

 

 

l          向项目中加入程序集引用

using VSLangProj;

 

private void AddReference(string assembly)

{

   Project project = GetSelectedProject();

   VSProject vsproject = null;

   if (project.Kind == PrjKind.prjKindCSharpProject)

   {

       //工程类型为C#工程,projectObject成员转换为VSProject对象

       vsproject = project.Object as VSProject;

   }

   if(vsproject != null)

   {

       //获取C#工程的引用集

       VSLangProj.References refers = vsproject.References;

       if(refers != null)

       {

           //将程序集引用添加到工程中

           refers.Add(assembly);

       }

   }

}

 

3、   在代码编辑窗口操纵代码

这里不再详述,只是列出网上的资源,大家可以自行参考

 

二、             参考资料

http://www.knowdotnet.com/add-insmacros.html

msdn帮助目录:Visual Studio .NET-->使用 Visual Studio .NET进行开发-->参考-->自动化与扩展性参考-->公共环境对象模型

 

三、             下载包说明:

CodeNavigator :演示了如何通过代码模型浏览代码

GuidGen      :演示了WinForm窗口在VS.NET集成环境中的应用

MenuBrowser   :演示了工具窗口的应用以及例举菜单对象的名称

RegionsAddIn  :用于添加#Region标签,演示了如何操纵代码编辑窗口

STDTools     :演示了如何向工程里添加文件,以及程序集引用,以及在工程项目的右键菜单上添加自己的菜单项

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值