VSTO 4.0 / Office 2007
In an Excel document-level automation project, I have a worksheet that must not be deleted from the workbook. 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.
Googling yielded the following VBA code:
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:
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 commandBa开发者_JAVA技巧r = 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.
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:
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:
<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. 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. 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)
精彩评论