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!");
}
The problem:
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:
- Identifying why it happens and solving it
- Suggesting another way of creating the button using a c# click handler
- Making it possible to save this sheet, close and reopen it with the events still attached.
A few more details:
- I am creating a new Excel application from C# code and taking the first sheet of the first workbook.
- This is not a VSTO Addin, I don't have access to the
Globals.Factory
, although I'd love to be able to get an instance of this factory and tryMicrosoft.Office.Tools.Worksheet
methods to add controls.- My project is inevitably a class library consumed by another non-related software
- The sheet must be saved and reopened later independently from the source project.
- The sheet is populated before adding the button, also via C# code.
- Visual Studio debugger is able to step into the button's event handler without any special action