【问题标题】:Sort Excel table (ListObject) on protected sheet using Excel Interop使用 Excel 互操作对受保护工作表上的 Excel 表 (ListObject) 进行排序
【发布时间】:2017-03-15 05:58:43
【问题描述】:

不允许在受保护的工作表上对 Excel 表格 (ListObjects) 进行排序。您将看到以下错误消息:

我花了数周时间寻找解决方案,但没有成功。 Excel 2007 代码示例中的所有内容都已过时。没有关于如何规避此限制的教程或指南。

这就是我最终克服的方法..

【问题讨论】:

    标签: vsto office365 excel-interop excel-2016 shared-addin


    【解决方案1】:

    从 Excel 的表格过滤器下拉菜单进行排序时,没有可捕获的事件。但是,当从功能区的“主页”和“数据”选项卡调用升序、降序或排序对话框命令时,您可以捕获事件。

    使用 Excel 2016 Interop(文档级自定义)、Visual Studio 2015 和 C#:


    1. 右键单击您的项目 -> 添加 -> 新项目 -> 功能区 (XML)

    2. 在您的 Ribbon.xml 上:

    <?xml version="1.0" encoding="UTF-8"?>
    <customUI xmlns="http://schemas.microsoft.com/office/2009/07/customui" onLoad="Ribbon_Load">
      <commands>  
        <command idMso="SortAscendingExcel" onAction="SortNoAlerts" />
        <command idMso="SortDescendingExcel" onAction="SortNoAlerts" />
        <command idMso="SortCustomExcel" onAction="SortDialogNoAlerts" /><!--TabHome-->
        <command idMso="SortDialog" onAction="SortDialogNoAlerts" /><!--TabData-->
      </commands>
    </customUI>
    

    接下来,添加事件的回调函数。 SortNoAlerts 取消对升/降按钮单击的工作表的保护。但是,如果用户选择“自定义排序”(主页选项卡)-或-“排序”(数据选项卡),则会出现一个对话框,确保它会取消保护工作表并如果按下确定,则立即保护它,但如果用户取消,ThisWorkbook_SheetCalculate 将永远不会触发使工作表不受保护。所以我们添加了SortDialogNoAlerts,它取消了工作表的保护,但也启动了一个使用 p/Invoke FindWindow 查找排序对话框窗口的计时器。当不再找到 Window 时,如果尚未受到保护,它会保护它。

    1. 在您的 Ribbon.cs 回调中:
        public void SortNoAlerts(Office.IRibbonControl control, ref bool cancelDefault)
        {
            Excel.Worksheet ws = null;
            try
            {
                ws = (Excel.Worksheet)Globals.ThisWorkbook.ActiveSheet;
                ws.Unprotect("your password");
                cancelDefault = false;
            }
            catch (Exception) { }
            finally
            {
                if (ws != null) Marshal.ReleaseComObject(ws); ws = null;
            }
        }
    
        public void SortDialogNoAlerts(Office.IRibbonControl control, ref bool cancelDefault)
        {
            Excel.Worksheet ws = null;
            try
            {
                ws = (Excel.Worksheet)Globals.ThisWorkbook.ActiveSheet;
                ws.Unprotect("your password");
                Globals.ThisWorkbook._myActionPane.tmrWaitSortWinClose.Enabled = true;
                cancelDefault = false;
            }
            catch (Exception) {
                Globals.ThisWorkbook._myActionPane.tmrWaitSortWinClose.Enabled = false;
            }
            finally
            {
                if (ws != null) Marshal.ReleaseComObject(ws); ws = null;
            }
        }
    
    1. 在 ThisWorkbook.cs -> InternalStartup() 添加:
    this.SheetCalculate += new Excel.WorkbookEvents_SheetCalculateEventHandler(ThisWorkbook_SheetCalculate);
    
    1. 在 ThisWorkbook.cs -> 添加:
    public bool sortDialogVisible;
    
    private void ThisWorkbook_SheetCalculate(object sh)
    {
      Excel.Worksheet ws = (Excel.Worksheet)sh;
      ws.EnableOutlining = true;
      ws.Protect("your password", true, Type.Missing, Type.Missing, true, true, true, Type.Missing, Type.Missing, true, Type.Missing, Type.Missing, true, true, true, Type.Missing);
      Marshal.ReleaseComObject(ws); ws = null;
    }
    
    1. 添加一个名为 tmrWaitSortWinClose 的计时器并设置 Interval = 750:
    private void tmrWaitSortWinClose_Tick(object sender, EventArgs e)
    {
        Globals.ThisWorkbook.sortDialogVisible = Native.FindWindow("NUIDialog", "Sort") == IntPtr.Zero;
    
        if (Globals.ThisWorkbook.sortDialogVisible)
        {
            Excel.Worksheet ws = null;
            try
            {
                ws = (Excel.Worksheet)Globals.ThisWorkbook.ActiveSheet;
    
                if (!ws.ProtectContents)
                {
                   ws.Protect("your password", true, Type.Missing, Type.Missing, true, true, true, Type.Missing, Type.Missing, true, Type.Missing, Type.Missing, true, true, true, Type.Missing);
                }
                tmrWaitSortWinClose.Enabled = false;
            }
            catch (Exception) { tmrWaitSortWinClose.Enabled = false; }
            finally
            {
                if (ws != null) Marshal.ReleaseComObject(ws); ws = null;
            }
        }
    }
    
    1. 添加一个名为 Native.cs 的类:
    public class Native
    {
        [DllImport("user32.dll", SetLastError = true)]
        public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
    }
    

    这将允许在受保护的工作表上对表格进行排序。不要混淆,worksheet.Protect()AllowSort 选项仅适用于不属于表格 (ListObject) 的工作表单元格。

    【讨论】:

      猜你喜欢
      • 2020-10-05
      • 2013-07-25
      • 1970-01-01
      • 2017-11-10
      • 2016-09-27
      • 2012-02-07
      • 2014-08-13
      • 2019-04-20
      • 2015-09-02
      相关资源
      最近更新 更多