You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在ThisAddIn.cs触发事件时修改Ribbon XML的getVisible属性

解决Word VSTO插件运行时动态隐藏Backstage保存选项卡的问题

我开发了一个Word VSTO插件,已通过DocumentOpen、DocumentBeforePrint和DocumentBeforeSave事件实现了根据文档和用户权限限制保存、打印及修改操作,插件运行正常。现在需要在DocumentBeforeSave事件触发且用户操作被阻止时,动态隐藏Backstage中的Save选项卡(TabSave)。

尝试过切换多个Ribbon XML但仅生效一次;也尝试使用getVisible和getEnabled属性,但不知道如何在事件中触发状态更新。

现有代码如下:

ThisAddIn.cs

public partial class ThisAddIn
{
    [DllImport("epsede.dll", CharSet = CharSet.Unicode)]
    public static extern int E1(int Event, IntPtr window, [MarshalAs(UnmanagedType.LPWStr)] String FileName);

    internal Ribbon1 Ribbon1;
    private void ThisAddIn_Startup(object sender, System.EventArgs e)
    {
        Globals.ThisAddIn.Application.DocumentBeforeSave += new Microsoft.Office.Interop.Word.ApplicationEvents4_DocumentBeforeSaveEventHandler(this.Application_DocumentBeforeSave);
    }

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

    //Before Save
    public void Application_DocumentBeforeSave(Microsoft.Office.Interop.Word.Document Doc, ref bool SaveAsUI, ref bool Cancel)
    {
        IntPtr hWnd = Process.GetCurrentProcess().MainWindowHandle;

        if (E1(2, hWnd, Doc.FullName) == 0)
        {
            // 允许保存
        }
        else
        {
            System.Windows.Forms.MessageBox.Show("Blocked Saving");
            Cancel = true;
            // 这里需要触发隐藏Save选项卡
        }
    }

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

    #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);
    }
    
    #endregion
}

Ribbon1.xml

<?xml version="1.0" encoding="UTF-8"?>
<customUI xmlns="http://schemas.microsoft.com/office/2009/07/customui" onLoad="Ribbon_Load">
    <backstage>
        <tab idMso ="TabSave" getVisible="IsTabSaveVisible" getEnabled="IsTabSaveEnabled"/>
    </backstage>
</customUI>

Ribbon1.cs

namespace WordS
{
    [ComVisible(true)]
    public class Ribbon1 : Office.IRibbonExtensibility
    {
        private Office.IRibbonUI ribbon;
        private bool _isSaveTabVisible = true;
        private bool _isSaveTabEnabled = true;

        // 控制Save选项卡可见性的属性
        public bool IsSaveTabVisible
        {
            get => _isSaveTabVisible;
            set
            {
                _isSaveTabVisible = value;
                ribbon?.InvalidateControlMso("TabSave"); // 仅刷新指定控件,比全局Invalidate更高效
            }
        }

        // 控制Save选项卡可用性的属性
        public bool IsSaveTabEnabled
        {
            get => _isSaveTabEnabled;
            set
            {
                _isSaveTabEnabled = value;
                ribbon?.InvalidateControlMso("TabSave");
            }
        }

        public Ribbon1()
        {
        }

        #region IRibbonExtensibility Members

        public string GetCustomUI(string ribbonID)
        {
            return GetResourceText("WordS.Ribbon1.xml");
        }

        #endregion

        #region Ribbon Callbacks

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

        // getVisible回调方法,必须与XML中指定的名称一致
        public bool IsTabSaveVisible(Office.IRibbonControl control)
        {
            return _isSaveTabVisible;
        }

        // getEnabled回调方法,可选,用于禁用而非隐藏
        public bool IsTabSaveEnabled(Office.IRibbonControl control)
        {
            return _isSaveTabEnabled;
        }
        
    }
}

实现步骤

  1. 完善Ribbon回调方法

    • 在Ribbon1.cs中添加与XML中getVisible、getEnabled对应的回调函数,名称必须完全匹配XML中的属性值。
    • 使用InvalidateControlMso替代全局Invalidate,只刷新目标控件(TabSave),提升性能。
  2. 在事件中更新状态
    修改ThisAddIn.cs中的Application_DocumentBeforeSave方法,当阻止保存时,更新Ribbon的状态:

    public void Application_DocumentBeforeSave(Microsoft.Office.Interop.Word.Document Doc, ref bool SaveAsUI, ref bool Cancel)
    {
        IntPtr hWnd = Process.GetCurrentProcess().MainWindowHandle;
        int result = E1(2, hWnd, Doc.FullName);
    
        if (result == 0)
        {
            // 允许保存时,恢复Save选项卡的可见性和可用性
            Ribbon1.IsSaveTabVisible = true;
            Ribbon1.IsSaveTabEnabled = true;
        }
        else
        {
            System.Windows.Forms.MessageBox.Show("Blocked Saving");
            Cancel = true;
            // 阻止保存时,隐藏并禁用Save选项卡
            Ribbon1.IsSaveTabVisible = false;
            Ribbon1.IsSaveTabEnabled = false;
        }
    }
    
  3. 处理文档切换场景
    若需要在打开新文档或切换文档时重新检查权限,可添加DocumentOpen和WindowActivate事件:

    private void ThisAddIn_Startup(object sender, System.EventArgs e)
    {
        Globals.ThisAddIn.Application.DocumentBeforeSave += Application_DocumentBeforeSave;
        Globals.ThisAddIn.Application.DocumentOpen += Application_DocumentOpen;
        Globals.ThisAddIn.Application.WindowActivate += Application_WindowActivate;
    }
    
    private void Application_WindowActivate(Microsoft.Office.Interop.Word.Document Doc, Microsoft.Office.Interop.Word.Window Wn)
    {
        CheckAndUpdateSaveTabPermission(Doc);
    }
    
    private void Application_DocumentOpen(Microsoft.Office.Interop.Word.Document Doc)
    {
        CheckAndUpdateSaveTabPermission(Doc);
    }
    
    private void CheckAndUpdateSaveTabPermission(Microsoft.Office.Interop.Word.Document Doc)
    {
        IntPtr hWnd = Process.GetCurrentProcess().MainWindowHandle;
        int result = E1(/* 传入对应检查权限的Event参数 */, hWnd, Doc.FullName);
        if (result == 0)
        {
            Ribbon1.IsSaveTabVisible = true;
            Ribbon1.IsSaveTabEnabled = true;
        }
        else
        {
            Ribbon1.IsSaveTabVisible = false;
            Ribbon1.IsSaveTabEnabled = false;
        }
    }
    

关键说明

  • Ribbon控件的状态更新必须通过Invalidate或InvalidateControlMso触发Office重新加载控件属性,直接修改变量不会生效。
  • 使用InvalidateControlMso("TabSave")比全局Invalidate()更高效,避免刷新整个Ribbon。
  • 若需要同时控制多个内置控件,可多次调用InvalidateControlMso,或使用Invalidate()刷新全部控件。

内容的提问来源于stack exchange,提问作者Maryam Ghayori

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 14:41:45