• C# Office Com 开发 创建任务窗格 CustomTaskPane


    在VSTO、ExcelDna的开发方式中,提供了非常容易的实现方法,而在Com开发下则必须自己实现,具体的方法就在下面的博主抄来的内容里。

     编译dll的时候注意选择32/64位

    以下内容除空格外都是从 DAVID E. CRAIG 这哥们儿的博客抄来的:

    CustomTaskPanes in a .NET Shared COM Add-in

    I was working with a customer that had a requirement to create a dynamic control for a CustomTaskPane in Excel and Word. In VSTO, this is very easy as the reference object found in ThisAddIn has a CustomTaskPanes collection. From there you can .Add() a CustomTaskPane and pass it a UserForm Control you build at runtime. This is very powerful in that you can create very dynamic TaskPanes. Smile

    With a COM Shared Add-in, however, this is not as easy. The main reason is that you have to directly implement the TaskPane interface Office.ICustomTaskPaneConsumer an it does not give you the nifty CustomTaskPanes collection. What it does give you is an ICTPFactory object which exposes a method called CreateCTP(). However, this method requires a registered ActiveX control CLSID name for the TaskPane control you want to appear in the pane. It will not accept a dynamically created User control. How this works is detailed here:

    ICustomTaskPaneConsumer.CTPFactoryAvailable Method (Office)
    http://msdn.microsoft.com/en-us/library/office/ff863874.aspx

    And this article details the full methodology:

    Creating Custom Task Panes in the 2007 Office System
    http://msdn.microsoft.com/en-us/library/office/aa338197%28v=office.12%29.aspx

    A fellow employee (http://blogs.msdn.com/b/cristib/) that also does a lot of blogging on VSTO, pointed me to a possible solution:

    • Use the method detailed in the second article
    • But create a VSTO UserForm Control and expose it as a COM Control
    • However, he suggested adding all the controls I might possibly need to the control form and show/hide them as needed. E.g. making it pseudo dynamic. But my customer needed a fully dynamic pane…

    So, I took it two steps further: Hot smile

    • First, I actually simplified the control idea greatly. My exposed COM control was a basic, simple, empty control. My design was to add the control to the TaskPane and then get a reference to the base UserForm control. From there I can call an exposed property (ChildControls) and then add anything I want to it. I can attach a button and then hook to it’s click event, etc. I can build a control dynamically at runtime, or build it as a separate project at design time.
    • Next, I recreated the CustomTaskPanes collection and CustomTaskPane objects in mirror classes so working with CustomTaskPanes in a Shared Add-in was as simple as in a VSTO add-in.

    First, lets look at the base control I created. You will see that I exposed it as COM Visible. After I built the project, I used REGASM to register it:

    C:WindowsMicrosoft.NETFrameworkv4.0.30319RegAsm.exe /codebase <path>CustomTaskPaneControl.BaseControl.dll

    Here is the code:

    [ComVisible(true)]
    [ProgId("CustomTaskPaneControl.BaseControl")]
    [Guid("DD38ADAB-F63A-4F4A-AC1A-343B385DA2AF")]
    public partial class BaseControl : UserControl
    {
        public BaseControl()
        {
            InitializeComponent();
        }
    
        [ComVisible(true)]
        public ControlCollection ChildControls
        {
            get
            {
                return this.Controls;
            }
        }
    }

    That is it – that is all there is. It is a simple placeholder, empty shell, ready to be filled with anything you add the the ChildControls property.

    Next, I created two new classes zCustomTaskPanesCollection and zCustomTaskPanes. I placed these in their own source code file and added it to the project Namespace. I also added the project reference to the base control above so I could directly cast it.

    Here is the code:

    /// <summary>
    /// This class mirrors the Office.CustomTaskPaneCollection
    /// </summary>
    public class zCustomTaskPaneCollection
    {
        // Public list of TaskPane items
        public List<zCustomTaskPane> Items = new List<zCustomTaskPane>();
        private Office.ICTPFactory _paneFactory;
    
        /// <summary>
        /// CTOR - takes the factor from the interface method
        /// </summary>
        /// <param name="CTPFactoryInst"></param>
        public zCustomTaskPaneCollection(Office.ICTPFactory CTPFactoryInst)
        {
            _paneFactory = CTPFactoryInst;
        }
    
        /// <summary>
        /// Adds a new TaskPane to the collection and takes a 
        /// User Form Control reference for the contents of the
        /// Control Pane
        /// </summary>
        /// <param name="control"></param>
        /// <param name="Title"></param>
        /// <returns></returns>
        public zCustomTaskPane Add(Control control, string Title)
        {
            // create a new Pane object
            zCustomTaskPane newPane = new zCustomTaskPane(control, Title, _paneFactory);
            Items.Add(newPane); // add it to the collection
            return newPane; // return a reference
        }
    
        /// <summary>
        /// Remove the specific pane from the list
        /// </summary>
        /// <param name="pane"></param>
        public void Remove(zCustomTaskPane pane)
        {
            Items.Remove(pane);
            pane.Dispose(); // dispose the pane
        }
    
        /// <summary>
        /// Get a list
        /// </summary>
        public int Count
        {
            get
            {
                return Items.Count;
            }
        }
    }
    
    /// <summary>
    /// This class mirrors the Office.CustomTaskPane class 
    /// </summary>
    public class zCustomTaskPane
    {
        private string _title = string.Empty;
        private Control _control = null;
        private Office.CustomTaskPane _taskPane;
        private BaseControl _base;
        public string Title { get { return _title; } }
        public event EventHandler VisibleChanged;
    
        /// <summary>
        /// Get or set the dock position of the TaskPane
        /// </summary>
        public Office.MsoCTPDockPosition DockPosition
        {
            get
            {
                return _taskPane.DockPosition;
            }
            set
            {
                _taskPane.DockPosition = value;
            }
        }
    
        /// <summary>
        /// Show or hide the CustomTaskPane
        /// </summary>
        public bool Visible
        {
            get
            {
                return _taskPane.Visible;
            }
            set
            {
                _taskPane.Visible = value;
            }
        }
    
        /// <summary>
        /// Reference to the control
        /// </summary>
        public Control Control { get { return _control; } }
    
        /// <summary>
        /// CTOR
        /// </summary>
        /// <param name="control"></param>
        /// <param name="Title"></param>
        /// <param name="CTPFactoryInst"></param>
        public zCustomTaskPane(Control control, string Title, Office.ICTPFactory CTPFactoryInst)
        {
            // create the taskpane control and use the factory to create a new instance of
            // our base control "CustomTaskPaneControl.BaseControl"
            _control = control;
            _title = Title;
            _taskPane = CTPFactoryInst.CreateCTP("CustomTaskPaneControl.BaseControl", Title);
            _taskPane.Width = control.Width + 2;
            _base = (BaseControl)_taskPane.ContentControl;
            _base.ChildControls.Add(control);
            _base.Height = control.Height + 2;
            // when the visibility changes fire an event
            _taskPane.VisibleStateChange += (Office.CustomTaskPane CustomTaskPaneInst) =>
                {
                    VisibleChanged(this, new EventArgs());
                };
        }
    
        /// <summary>
        /// Dispose of the control and collect
        /// </summary>
        public void Dispose()
        {
            try
            {
                _taskPane.Visible = false;
            }
            catch { }
            try
            {
                _control.Dispose();
                _control = null;
                _base.Dispose();
                _base = null;
            }
            catch { }
            GC.Collect();
            GC.Collect();
            GC.WaitForPendingFinalizers();
        }
    }

    Finally, I added hooked up my Shared Add-in to use the ICustomTaskPaneConsumer interface. At that point, everything was hooked up ready to go:

    public class Connect : Object, Extensibility.IDTExtensibility2, Office.ICustomTaskPaneConsumer, Office.IRibbonExtensibility
    {
        public zCustomTaskPaneCollection CustomTaskPaneCollection;
        void Office.ICustomTaskPaneConsumer.CTPFactoryAvailable(Office.ICTPFactory CTPFactoryInst)
        {
            CustomTaskPaneCollection = new zCustomTaskPaneCollection(CTPFactoryInst);
        }

    Now, I was able to build a fully dynamic control on a Ribbon Button click, like this:

    // create a dynamic control on the fly
    UserControl dynamicControl = new UserControl();
    // add a button to it
    Button btnTest = new Button();
    btnTest.Name = "btnTest";
    btnTest.Text = "Hello";
    // when the user clicks the button on the TaskPane,
    // say hello...
    btnTest.Click +=(object sender, EventArgs e) =>
        {
            MessageBox.Show("Hello World!");
        };
    // add the button to the control 
    dynamicControl.Controls.Add(btnTest);
    // now create the taskPane - looks exactly the same
    // as how you would create one in VSTO
    zCustomTaskPane myPane = CustomTaskPaneCollection.Add(dynamicControl, "My Pane");
    myPane.VisibleChanged += (object sender, EventArgs e) =>
        {
            // when the taskpane is hidden, invalidate the ribbon
            // so my toggle button can toggle off
            ribbon.Invalidate();
        };
    // dock to the right
    myPane.DockPosition = Office.MsoCTPDockPosition.msoCTPDockPositionRight;
    // show it
    myPane.Visible = true;

    Once fully implemented this looks and acts just like the CustomTaskPaneCollection from VSTO and is just as easy to use and allows you to create dynamic, on the fly controls. Winking smile

    原博客URL:https://theofficecontext.com/2013/05/21/customtaskpanes-in-a-net-shared-com-add-in/

  • 相关阅读:
    Activiti服务类-1 DynamicBpmnService服务类
    Activiti工作流学习(一)——Activiti服务类
    怎么才能将文件流或者图片转化为base64,传到前台展示
    idea导入eclipse项目
    使用IDEA开发Activiti工作流
    idea中创建多module的maven工程
    Git的使用--如何将本地项目上传到Github
    Spring Boot 入门搭建
    Json中相同或者重复记录的值相加组成新的Json
    前端基础之jQuery入门 01
  • 原文地址:https://www.cnblogs.com/yzhyingcool/p/13872801.html
Copyright © 2020-2023  润新知