首页 > 解决方案 > Excel VSTO如何在触发WorkbookBeforeClose事件后检查是否已从对话框中触发了取消按钮?

问题描述

我目前正在开发 Excel VSTO 插件,这是 WorkbookBeforeClose 的代码

private void App_WorkbookBeforeClose(Excel.Workbook Wb, ref bool Cancel)
    {
        bool isEnabled = false;
        setRibbonControlState(ref isEnabled);
    }

在此代码中,如果没有打开任何工作簿,我将禁用功能区。但是,如果我在尝试关闭 Excel 后按下对话框中的取消按钮,则功能区无论如何都会被禁用。但是由于 WorkbookBeforeClose 事件传递了一个 Cancel 参数,我不知道当我按下按钮时如何设置该参数,如何检查提示已触发按钮的对话框。

到目前为止,我看到的所有案例都在 WorkbookBeforeClose 处理程序的主体中实现了一个对话框,但我不想实现自定义对话框,我想使用默认提供的对话框。

谢谢!

标签: c#excelvsto

解决方案


根据我的 VBA 经验

但我不想实现自定义对话框,我想使用默认提供的对话框。

是不可能的,因为该对话框出现在before_close事件之后。
管理这些东西的唯一(我知道的)方法是创建自己的SaveChanges对话框,顺便说一句,这非常简单,并不是每个用户都会注意到其中的区别。而且,它会做与默认提示相同的工作。
您应该注意的另一件事 - 可能至少有一个不可见的工作簿。即使您看到这样的屏幕:
在此处输入图像描述 也有可能this.Application.Workbooks.Count会显示 1,而不是 0。这是因为用户可能拥有自己的 Personal.xlsb 工作簿,该工作簿是不可见的,但仍然加载了 Excel。应用。因此,如果您想正确禁用功能区 - 您也应该考虑这一点。

这是我的这个解决方案的例子:

public partial class ThisAddIn
    {
        private void ThisAddIn_Startup(object sender, System.EventArgs e)
        {
            this.Application.WorkbookBeforeClose += ApplicationOnWorkbookBeforeClose;
        }

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

        // Catch the before close event
        private void ApplicationOnWorkbookBeforeClose(Excel.Workbook wb, ref bool cancel)
        {

            if (!wb.Saved)
            {
                switch (MessageBox.Show(text:$"Do you want to save changes you made to '{this.Application.ActiveWorkbook.Name}'?", 
                    caption:"Microsoft Excel",buttons:MessageBoxButtons.YesNoCancel, icon:MessageBoxIcon.Exclamation))
                {
                    case DialogResult.Cancel: // case want to cancel - break the closing event
                        {
                            cancel = true;
                            return;
                        }
                    case DialogResult.Yes: // case user want to save wb - save wb
                        {
                            wb.Save();
                            break;
                        }
                    case DialogResult.No: // case user don't want to save wb - mark wb as saved to avoid the application messagebox to appear
                        {
                            wb.Saved = true;
                            break;
                        }
                }
            }

            if (IsAnyWorkbookOpen())
            {
                // replace this with your code
                MessageBox.Show("Some books will still be open, don't turn off the ribbon");
                return;
            }
            // replace this with your code
            MessageBox.Show("All books will be closed");
        }

        private bool IsAnyWorkbookOpen()
        {
            // check that remaining amount of open workbooks without the one being closed is greater that 2
            if (this.Application.Workbooks.Count - 1 > 2)
            {
                return true;
            }
            // IF the count of workbooks is 2 one of them maybe a PERSONAL.xlsb
            else if (this.Application.Workbooks.Count == 2)
            {
                foreach (Excel.Workbook wb in this.Application.Workbooks)
                {
                    if (!wb.Name.Equals(this.Application.ActiveWorkbook.Name))
                    {
                        // In case when one of two open workbooks is Personal macro book you may assume that 
                        // there will be no open workbooks for user to work directly
                        if (wb.Name.Equals("Personal.xlsb".ToUpper()))
                        {
                            return false;
                        }
                    }
                }
                // In case when NONE of two open workbooks is a Personal macro book
                // there will be at least one open workbook for user to work directly
                return true;
            }
            else
            {
                return true;
            }
        }


        #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
    }

最后一件事 - 如果您禁用功能区,但应用程序仍将运行 - 您必须在workbook_activate事件中再次启用它。

请注意,我只是从 VBA 转移到 VSTO - 所以任何评论都非常感谢。


推荐阅读