通过Workbook_Open事件更改VSTO选项卡的可见属性

时间:2017-06-27 21:12:10

标签: c# excel vsto

我为Excel VSTO项目编写了Ribbon.xml文件。 tab元素如下所示:

<tab id="myId" idMso="TabAddIns" label="My Tab" visible="false">

打开工作簿时,我希望默认情况下隐藏选项卡,这是通过将visible属性设置为false来完成的。接下来,我想在Workbook_Open事件中将visible属性更改为true。这就是我被困的地方。我不会认为这很难,但我花了几个小时在Google上搜索答案。似乎大多数示例1)通过button callback来切换标签的可见性,这不是我想要做的,或2)能够访问ribbon's properties,我没有到目前为止能够复制(尽管这些资源中的大部分都是旧的,所以我认为MS从那时起就移动了这些属性)。

有没有人知道如何轻松地将visible属性更改为true以便显示选项卡?

谢谢!

更新了附加信息:

ThisAddIn.cs

namespace Doodles_Reporting
{
    public partial class ThisAddIn
    {
        public RibbonApi ribbonApi;


        private void ThisAddIn_Startup(object sender, System.EventArgs e)
        {
        }

        private void ThisAddIn_Shutdown(object sender, System.EventArgs e)
        {
        }

        protected override Microsoft.Office.Core.IRibbonExtensibility CreateRibbonExtensibilityObject()
        {
            return new Ribbon();
        }

        void Application_WorkbookOpen(Excel.Workbook Wb)
        {

            //first, check if there is an application/process for each workbook
            Excel.Workbooks books = Globals.ThisAddIn.Application.Workbooks;
            if (books.Count > 1)
            {
                try
                {
                    //close workbook that was just opened and then reopen it with new process/application.
                    string filePath = Wb.FullName;
                    Wb.Close();
                    Excel.Application excelApp = new Excel.Application();
                    excelApp.Visible = true;
                    excelApp.DisplayFullScreen = true;
                    excelApp.Workbooks.Open(filePath);
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK);
                }
            }
            else
            {
                //second, check if the workbook is a Doodles workbook
                try
                {
                    DocumentProperties props = (DocumentProperties)Wb.CustomDocumentProperties;
                    var selectedTable = props["selectedTable"].Value;
                    configureDoodles();
                }
                catch (Exception)
                {
                 //THIS IS WHERE I WANT TO SET THE RIBBON VISIBILITY TO FALSE
                }
            }   
        }

        private void configureDoodles()
        {
            RibbonApi.app = Globals.ThisAddIn.Application;
            RibbonApi.wBookPropertiesConfig = new WorkbookPropertiesConfig(RibbonApi.app.ActiveWorkbook);
            RibbonApi.presenter = new ExcelPresenter(RibbonApi.app.ActiveWorkbook);
            ribbonApi = new RibbonApi();
        }

        #region VSTO generated code

        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InternalStartup()
        {
            this.Startup += new System.EventHandler(ThisAddIn_Startup);
            this.Shutdown += new System.EventHandler(ThisAddIn_Shutdown);
            this.Application.WorkbookOpen += new Excel.AppEvents_WorkbookOpenEventHandler(Application_WorkbookOpen);
        }

        #endregion
    }
}

Ribbon.cs

namespace Doodles_Reporting
{
    [ComVisible(true)]
    public class Ribbon : Office.IRibbonExtensibility
    {
        private Office.IRibbonUI ribbon;

        public Ribbon()
        {
        }

        #region IRibbonExtensibility Members

        public string GetCustomUI(string ribbonID)
        {
            return GetResourceText("Doodles_Reporting.Ribbon.xml");
        }

        #endregion

        #region Ribbon Callbacks
        //Create callback methods here. For more information about adding callback methods, visit http://go.microsoft.com/fwlink/?LinkID=271226

        public void Ribbon_Load(Office.IRibbonUI ribbonUI)
        {
            this.ribbon = ribbonUI;
        }

        public bool toggleVisibility(Office.IRibbonControl control)
        {
            return (control.Id == "TabAddIns") ? true : false;
        }

        public void onSomeEvent()
        {
            this.ribbon.InvalidateControl("TabAddIns");
        }

        public void SignIn(Office.IRibbonControl ribbonUI)
        {
            Globals.ThisAddIn.ribbonApi.signIn();
        }

        public void SqlCreatorFormLoad(Office.IRibbonControl ribbonUI)
        {
            Globals.ThisAddIn.ribbonApi.showSqlCreator();
        }

        public void refreshData(Office.IRibbonControl ribbonUI)
        {
            Globals.ThisAddIn.ribbonApi.refreshData();
        }

        public void drilldownSelectionLoad(Office.IRibbonControl ribbonUI)
        {
            Globals.ThisAddIn.ribbonApi.setDrilldownColumns();
        }

        public void Drilldown(Office.IRibbonControl ribbonUI)
        {
            Globals.ThisAddIn.ribbonApi.drilldown();
        }

        public void editProperties(Office.IRibbonControl ribbonUI)
        {

        }

        #endregion

        #region Helpers

        private static string GetResourceText(string resourceName)
        {
            Assembly asm = Assembly.GetExecutingAssembly();
            string[] resourceNames = asm.GetManifestResourceNames();
            for (int i = 0; i < resourceNames.Length; ++i)
            {
                if (string.Compare(resourceName, resourceNames[i], StringComparison.OrdinalIgnoreCase) == 0)
                {
                    using (StreamReader resourceReader = new StreamReader(asm.GetManifestResourceStream(resourceNames[i])))
                    {
                        if (resourceReader != null)
                        {
                            return resourceReader.ReadToEnd();
                        }
                    }
                }
            }
            return null;
        }

        #endregion
    }
}

4 个答案:

答案 0 :(得分:2)

丝带是一个有趣的野兽。它专门设计为禁止您直接访问其任何元素,并禁止您直接操作它们。相反,一切都是通过回调完成的。我没有很多VSTO的经验,但我可以解释一下你在没有VSTO的情况下用C#或C ++做什么,我相信你可以填补空白。

  1. 在功能区XML中设置onLoad回调。首次加载功能区时,Excel将调用此方法(通过IDispatch)。

    <customUI ... onLoad="OnRibbonLoaded">
    
  2. 实施onLoad回调,该回调应存储所提供的IRibbonUI引用。

    public void OnRibbonLoaded(IRibbonUI ribbon)
    {
        this.ribbon = ribbon;
    }
    
  3. 对于要动态控制的属性,请在功能区XML中定义回调。

    <tab ... getVisible="GetVisible">
    
  4. 实施可见性回调。如果功能区的多个部分使用相同的回调,则传入此方法的IRibbonControl实例可用于确定要查询的选项卡/组/控件。

    public bool GetVisible(IRibbonControl control)
    {
        // here is where you should determine if your tab/group/control should be visible,
        return (some condition) ? true : false;
    }
    
  5. 每当您决定要更新可见性时,请告诉Excel使用IRibbonUI引用重新查询您控件的属性(即调用您的回调)。

    void OnSomeEvent()
    {
        // you can tell Excel to update the entire ribbon
        this.ribbon.Invalidate();
    
        // or you can tell Excel to update a single tab/group/control
        this.ribbon.InvalidateControl("my_id");
    }
    

答案 1 :(得分:2)

你已经收到了所有的碎片。

ThisAddin中,您要覆盖CreateRibbonExtensibilityObject。而不是返回new Ribbon,而是返回一个你持有的对象。

public partial class ThisAddIn
{
    private readonly Ribbon _ribbon = new Ribbon();

    protected override Microsoft.Office.Core.IRibbonExtensibility CreateRibbonExtensibilityObject()
    {
        return this._ribbon;
    }
}

然后,向该对象添加公开Invalidate()方法,或将该对象的IRibbonUI字段设为公开并致电Invalidate / InvalidateControl在那。我可能会做前者。

[ComVisible(true)]
public class Ribbon : Office.IRibbonExtensibility
{
    private Office.IRibbonUI _ribbonUI;

    public void Invalidate()
    {
        this._ribbonUI.Invalidate();
    }

    public void InvalidatePlayButton()
    {
        this._ribbonUI.Invalidate("PlayButton");
    }
}

然后从Application_WorkbookOpen调用这些公开方法。

public partial class ThisAddIn
{
    void Application_WorkbookOpen(Excel.Workbook Wb)
    {
        this._ribbon.Invalidate();
        this._ribbon.InvalidatePlayButton();
    }
}

请注意,如果您愿意,可以将这些对象组合到单个对象中。只需ThisAddin实施Microsoft.Office.Core.IRibbonExtensibility并从this返回CreateRibbonExtensibilityObject

但是,创建单独的对象有一些优点。例如,将功能区封装在更强大的公共方法和属性中变得很容易。例如:

public class Ribbon : Office.IRibbonExtensibility
{
    private Office.IRibbonUI _ribbonUI;

    private bool _isPlayButtonVisible = true;

    // here's a property that makes it easy to update the visibility of the play button
    public bool IsPlayButtonVisible
    {
        get { return this._isPlayButtonVisible; }
        set
        {
            if (this._isPlayButtonVisible != value)
            {
                this._isPlayButtonVisible = value;
                this._ribbonUI.InvalidateControl("PlayButton");
            }
        }
    }

    // here's the callback that Excel will call
    public bool GetIsPlayButtonVisible(IRibbonControl control)
    {
        return this.IsPlayButtonVisible
    }
}

答案 2 :(得分:1)

对于想知道如何使用设计师的缎带进行此操作的人:

如果您尝试过此操作:

Globals.Ribbons.MyRibbon.MyRibbonTab.Visible = false;

什么也没有发生,请尝试将所有功能区组设置为Visible = false。 当功能区中的所有功能区组都不可见时,整个功能区将自动设置为Visible = false。

private void SetRibbonVisibility(bool visible)
    {
        foreach (var ribbonGroup in Globals.Ribbons.Ribbon.MyRibbonTab.Groups)
        {
            ribbonGroup.Visible = visible;
        }
    }

是的,与VSTO合作很愉快。

答案 3 :(得分:0)

因此,我发现使用功能区设计器使这更加简单。创建新的Ribbon Designer类后,该类将添加到Globals.Ribbons下的对象模型中。所有这些意味着隐藏选项卡变得像我认为应该使用一行代码一样简单:

Globals.Ribbons.RibbonVisual.Doodles.Visible = false;

其中RibbonVisual是我创建的Ribbon Designer类的名称,Doodles是选项卡的名称。

从现在开始我将使用Ribbon Designer lol:P。