I was trying to create an Excel button in a sheet from a C# code, using a C# event hander for the button, so I don't have to involve VBA and text scripts; and I found this great solution from @ Dummy yoyo that works but "only for a while".
The solution is simple: add a shape, get it as an ole object, get the ole as a button and add a click event:
int i = 1;
private void CreateButton()
{
Microsoft.Office.Interop.Excel.Worksheet sheet = #get a sheet from Excel
sheet.Shapes.AddOLEObject("Forms.CommandButton.1", Type.Missing, false, false, Type.Missing, Type.Missing, Type.Missing, 10, 10, 100, 30);
Microsoft.Office.Interop.Excel.OLEObject oleShape = sheet.OLEObjects(1);
Microsoft.Vbe.Interop.Forms.CommandButton button = oleShape.Object;
button.Caption = "Custom Buttom" + i;
button.Click += Button_Click;
i++; //for future use, see below
}
private void Button_Click()
{
MessageBox.Show("It works!");
}
Now, the first time I click the button on the sheet, it works! The second time "might" work. The more clicks the less chance of it working. Inevitably, the button "loses" the click event and just does nothing. I can't figure out why, what can be causing this.
I even tried to recreate the button every click with:
private void Button_Click()
{
MessageBox.Show("It Works!");
sheet.Shapes.Item(1).Delete();
CreateButton();
}
I can see the button is being recreated because of the i++ that shows in the button's caption. Even though, some clicks later, even the newly created button simply does nothing when clicked.
What can be going on? How can I solve this?
Edit:
A partial solution was found, as @Hans Passant suggested: if I keep the shape, the ole object and the button as static members outside the method, the garbage collector doesn't kill them. Nevertheless, I would like to save, close and reopen the sheet and still get the events.
Great solutions could be:
A few more details:
Globals.Factory, although I'd love to be able to get an instance of this factory and try Microsoft.Office.Tools.Worksheet methods to add controls.