zoukankan      html  css  js  c++  java
  • 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/

  • 相关阅读:
    access 连接数据库
    Debug 和 Release 的区别
    Centos
    打印画面
    读取文件夹以及消除
    常用的文件文件夹目录的操作函数
    db的操作
    从数据库取数据
    pdf文件的作成
    读取文件
  • 原文地址:https://www.cnblogs.com/yzhyingcool/p/13872801.html
Copyright © 2011-2022 走看看