不允许在受保护的工作表上对 Excel 表 (ListObjects) 进行排序。您将看到以下错误消息:
我花了数周时间寻找没有成功的解决方案。Excel 2007 代码示例中的所有内容都已过时。没有关于如何规避此限制的教程或指南。
这就是我最终克服的方法。
不允许在受保护的工作表上对 Excel 表 (ListObjects) 进行排序。您将看到以下错误消息:
我花了数周时间寻找没有成功的解决方案。Excel 2007 代码示例中的所有内容都已过时。没有关于如何规避此限制的教程或指南。
这就是我最终克服的方法。
从 Excel 的表格过滤器下拉菜单进行排序时,没有可捕获的事件。但是,当从功能区的“主页”和“数据”选项卡调用升序、降序或排序对话框命令时,您可以捕获事件。
使用 Excel 2016 互操作(文档级自定义)、Visual Studio 2015 和 C#:
右键单击您的项目 -> 添加 -> 新项目 -> 功能区 (XML)
在您的 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/InvokeFindWindow
来查找“排序”对话框窗口。当不再找到 Window 时,如果尚未受到保护,它会保护它。
- 在您的 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;
}
}
- 在 ThisWorkbook.cs -> InternalStartup() 添加:
this.SheetCalculate += new Excel.WorkbookEvents_SheetCalculateEventHandler(ThisWorkbook_SheetCalculate);
- 在 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;
}
- 添加一个名为 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;
}
}
}
- 添加一个名为 Native.cs 的类:
public class Native
{
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
}
这将允许在受保护的工作表上对表格进行排序。不要混淆,它的AllowSort
选项worksheet.Protect()
仅适用于不属于表格 (ListObject) 的工作表单元格。