简体   繁体   English

Excel Automation:保护单个工作表不被用户删除

[英]Excel Automation: Protect single worksheet from deletion by user

VSTO 4.0 / Office 2007 VSTO 4.0 / Office 2007

In an Excel document-level automation project, I have a worksheet that must not be deleted from the workbook . 在Excel文档级自动化项目中,我有一个工作表, 一定不能从工作簿中删除 I am afraid that a careless user might delete it by accident, which currently causes a lot of grief (exceptions galore). 恐怕粗心的用户可能会意外删除它,这当前会引起很多麻烦(异常丰富)。

I can not protect the entire workbook, because the user must be able to create, delete and otherwise modify this file. 我不能保护整个工作簿,因为用户必须能够创建,删除和修改此文件。 Exactly one sheet needs to be protected from deletion, but I may be overlooking something, so if there exists such solution I'm all ears. 确实需要保护一张纸不被删除,但是我可能忽略了某些东西,因此,如果存在这样的解决方案,我将不知所措。 For example I could imagine that I can Protect() and Unprotect() the workbook when the sheet is visible, but this solution seems messy. 例如,我可以想象当工作表可见时我可以对工作簿进行Protect()Unprotect() ,但是这种解决方案似乎很混乱。

Googling yielded the following VBA code: Googling 产生了以下VBA代码:

Private Sub Worksheet_Activate()
Dim CB As CommandBar
Dim Ctrl As CommandBarControl
For Each CB In Application.CommandBars
Set Ctrl = CB.FindControl(ID:=847, recursive:=True)
If Not Ctrl Is Nothing Then
Ctrl.OnAction = "RefuseToDelete"
Ctrl.State = msoButtonUp
End If
Next
End Sub

I'm not familiar with VBA, but I tried running this from the VSTO generated startup method: 我不熟悉VBA,但是我尝试从VSTO生成的启动方法中运行它:

private void Sheet1_Startup(object sender, System.EventArgs e)
{
    //Is there a neater way to iterate through all Office Collections?
    for (var i = 1; i <= Application.CommandBars.Count; i++)
    {
        var commandBar = Application.CommandBars[i];
        //847 is a magical constant that any fule no has something to do with sheet deletion
        var control = commandBar.FindControl(Id: 847, Recursive: true);
        if (control != null) control.OnAction = null;
    }
}

This code seems to do exactly nothing. 这段代码似乎什么也没做。 You may ask "Hey, Gleno, why are you setting OnAction to null" , well I don't know what to set it to... The linked VBA solution attaches to Activate and Deactivate events, so there's more code where that came from. 您可能会问“嘿,Gleno,为什么要将OnAction设置为null” ,我不知道将其设置为什么...链接的VBA解决方案附加到Activate和Deactivate事件,因此有更多代码来自。

Thanks in advance. 提前致谢。

I had to do something very similar today. 今天我不得不做一些非常相似的事情。 I would just disable the sheet delete buttons whenever your one "undeleteable" sheet is active. 只要您的一个“不可删除”工作表处于活动状态,我就禁用工作表删除按钮。 If there's a keyboard shortcut to delete a sheet, I can't find one. 如果有用于删除工作表的键盘快捷键,我找不到它。 (If there is, you could disable that too.) (如果有,您也可以禁用它。)

This would go in your ThisWorkbook class: 这将在您的ThisWorkbook类中:

    private void ThisWorkbook_Startup(object sender, System.EventArgs e)
    {
        this.SheetActivate += (sh) =>
            {
                this.ribbon.InvalidateBuiltinControl("SheetDelete");
            };
    }

    public bool CanDeleteActiveSheet()
    {
        if (this.ActiveSheet == null)
            return true;

        // Replace Sheet1 with your sheet's CodeName
        return ((Excel.Worksheet)this.ActiveSheet).CodeName != "Sheet1";
    }

    // Keep a local reference to the ribbon in your ThisWorkbook class
    // so you can call InvalidateControl() from it.
    Ribbon ribbon;
    protected override IRibbonExtensibility CreateRibbonExtensibilityObject()
    {
        this.ribbon = new Ribbon();
        return this.ribbon;
    }

This would go in your ribbon code behind: 这将放在您的功能区代码后面:

    public void InvalidateBuiltinControl(string controlID)
    {
        this.ribbon.InvalidateControlMso(controlID);
    }

    public bool deleteButton_GetEnabled(IRibbonControl control)
    {
        return Globals.ThisWorkbook.CanDeleteActiveSheet();
    }

And this would go in your ribbon xml: 这将放在您的功能区xml中:

<commands>
    <command idMso="SheetDelete" getEnabled="deleteButton_GetEnabled" />
</commands>

I'm still a little leery of holding on to that ribbon reference in ThisWorkbook, but so far no one has mentioned a better way in the question I posted earlier . 我仍然对在ThisWorkbook中保留该功能区引用有些不满意,但是到目前为止, 在我先前发布的问题没有人提到更好的方法。 Hope this helps! 希望这可以帮助!

I'm having a similar problem where I know how to protect the worksheet but I need to turn protection on after the sheet has been populated with external data from a SQL connection. 我有一个类似的问题,我知道如何保护工作表,但是在工作表中填充了来自SQL连接的外部数据后,我需要打开保护。 I cannot locate the correct event to do this. 我无法找到正确的事件来执行此操作。

This should help you put it in the startup event for the worksheet: 这应该可以帮助您将其放在工作表的启动事件中:

Me.Protect(password:="password", allowFiltering:=True, allowSorting:=True, allowUsingPivotTables:=True) Me.Protect(密码:=“密码”,allowFiltering:=真实,allowSorting:=真实,allowUsingPivotTables:=真实)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM