Excel OLEObject按钮点击几次后丢失点击事件

发布于 2025-01-16 02:02:31 字数 2194 浏览 6 评论 0原文

我试图在工作表中从 C# 代码创建一个 Excel 按钮,使用按钮的 C# 事件处理程序,所以我不这样做不必涉及 VBA 和文本脚本;我发现来自 @ 的这个出色的解决方案 假溜溜球可以工作,但“只能持续一段时间”。

解决方案很简单:添加一个形状,将其作为 ole 对象获取,将 ole 作为按钮获取并添加单击事件:

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!");
}

问题:

现在,我第一次单击工作表上的按钮时,它起作用了!第二次“可能”有效。点击次数越多,它起作用的机会就越小。不可避免的是,按钮“丢失”了点击事件并且什么也不做。我不明白为什么,可能是什么原因造成的。

我什至尝试在每次点击时重新创建按钮:

private void Button_Click()
{
    MessageBox.Show("It Works!");
    sheet.Shapes.Item(1).Delete();
    CreateButton();
}

我可以看到按钮正在重新创建,因为按钮标题中显示了 i++ 。即使稍后单击了一些,即使是新创建的按钮在单击时也不会执行任何操作。

会发生什么情况?我该如何解决这个问题?

编辑:

找到了部分解决方案,正如@Hans Passant建议的那样:如果我将形状、ole 对象和按钮保留为方法外部的静态成员,则垃圾收集器不会杀死他们。尽管如此,我想保存、关闭并重新打开工作表,但仍然可以获得事件。

好的解决方案可能是:

  • 确定发生这种情况的原因并解决它
  • 建议使用 c# 单击处理程序 创建按钮的另一种方法
  • 可以保存此工作表,关闭并重新打开它,同时仍附加事件。

更多细节:

  • 我正在从 C# 代码创建一个新的 Excel 应用程序,并获取第一个工作簿的第一张工作表。
  • 这不是 VSTO 插件,我无权访问 Globals.Factory,尽管我很乐意能够获取该工厂的实例并尝试用于添加控件的 Microsoft.Office.Tools.Worksheet 方法。
    • 我的项目不可避免地是一个被另一个不相关的软件消耗的类库
  • 该工作表必须独立于源项目保存并稍后重新打开。
  • 该工作表是在添加按钮之前填充的,也是通过 C# 代码填充的。
  • Visual Studio 调试器能够单步进入按钮的事件处理程序,无需任何特殊操作

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 try Microsoft.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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

左岸枫 2025-01-23 02:02:31

每次我单击此按钮时都遵循以下方式,没有遇到任何问题。

        using Excel = Microsoft.Office.Interop.Excel;
        Excel.Application xlApp;
        Excel.Workbook xlWorkBook;
        Excel.Worksheet xlWorkSheet;

        object misValue = System.Reflection.Missing.Value;

        int i = 1;
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {

            xlApp = new Excel.Application();
            xlWorkBook = xlApp.Workbooks.Add(misValue);
            xlWorkSheet = (Excel.Worksheet)xlWorkBook.Worksheets.get_Item(1);

            //add data 
            xlWorkSheet.Cells[1, 1] = "";
            xlWorkSheet.Cells[1, 2] = "Student1";
            xlWorkSheet.Cells[1, 3] = "Student2";
            xlWorkSheet.Cells[1, 4] = "Student3";

            xlWorkSheet.Cells[2, 1] = "Term1";
            xlWorkSheet.Cells[2, 2] = "80";
            xlWorkSheet.Cells[2, 3] = "65";
            xlWorkSheet.Cells[2, 4] = "45";

            xlWorkSheet.Cells[3, 1] = "Term2";
            xlWorkSheet.Cells[3, 2] = "78";
            xlWorkSheet.Cells[3, 3] = "72";
            xlWorkSheet.Cells[3, 4] = "60";
            xlApp.Visible = true;

            #region

            xlWorkSheet.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 = xlWorkSheet.OLEObjects(1);
            Microsoft.Vbe.Interop.Forms.CommandButton button = oleShape.Object;
            button.Caption = "Custom Buttom" +i ;

            button.Click += Button_Click;
            i++; 
            #endregion
        }

        private void Button_Click()
        {
            MessageBox.Show("It works!");
        }

输入图片此处的描述

但有时按钮似乎不可点击或什至无法点击。请参阅下面的屏幕截图。

输入图片此处的说明

消息已显示,但我们在工作表顶部看不到它。点击按钮次数过多可能会发生这种情况。因此,如果您没有看到该对话框,只需从任务栏打开它。

输入图像此处描述
重新打开:保存并关闭文档或工作簿时,在运行时添加的控件不会保留。宿主控件和 Windows 窗体控件的确切行为是不同的。在这两种情况下,您都可以将代码添加到解决方案中,以便在用户重新打开文档时重新创建控件。

           xlApp = new Excel.Application();
            string workbookPath = @"c:/Book.xlsx";
            xlWorkBook = xlApp.Workbooks.Open(workbookPath,
                    0, false, 5, "", "", false, Excel.XlPlatform.xlWindows, "",
                    true, false, 0, true, false, false);

            xlWorkSheet = (Excel.Worksheet)xlWorkBook.Worksheets.get_Item(1);

            xlApp.Visible = true;

            Microsoft.Office.Interop.Excel.OLEObject oleShape = xlWorkSheet.OLEObjects(1);
            Microsoft.Vbe.Interop.Forms.CommandButton button = oleShape.Object;
            button.Caption = "Custom Buttom" + i;

            button.Click += Button_Click;
            i++;

注意:Microsoft Excel 2013、项目参考 Microsoft Office 15.0 对象库 和 VS 2022 工作正常,但 Excel 2016 存在您所说的这个问题。所以我认为这个问题来自
Microsoft Office 特定版本。

Following way every time I click on this button not getting any issue.

        using Excel = Microsoft.Office.Interop.Excel;
        Excel.Application xlApp;
        Excel.Workbook xlWorkBook;
        Excel.Worksheet xlWorkSheet;

        object misValue = System.Reflection.Missing.Value;

        int i = 1;
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {

            xlApp = new Excel.Application();
            xlWorkBook = xlApp.Workbooks.Add(misValue);
            xlWorkSheet = (Excel.Worksheet)xlWorkBook.Worksheets.get_Item(1);

            //add data 
            xlWorkSheet.Cells[1, 1] = "";
            xlWorkSheet.Cells[1, 2] = "Student1";
            xlWorkSheet.Cells[1, 3] = "Student2";
            xlWorkSheet.Cells[1, 4] = "Student3";

            xlWorkSheet.Cells[2, 1] = "Term1";
            xlWorkSheet.Cells[2, 2] = "80";
            xlWorkSheet.Cells[2, 3] = "65";
            xlWorkSheet.Cells[2, 4] = "45";

            xlWorkSheet.Cells[3, 1] = "Term2";
            xlWorkSheet.Cells[3, 2] = "78";
            xlWorkSheet.Cells[3, 3] = "72";
            xlWorkSheet.Cells[3, 4] = "60";
            xlApp.Visible = true;

            #region

            xlWorkSheet.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 = xlWorkSheet.OLEObjects(1);
            Microsoft.Vbe.Interop.Forms.CommandButton button = oleShape.Object;
            button.Caption = "Custom Buttom" +i ;

            button.Click += Button_Click;
            i++; 
            #endregion
        }

        private void Button_Click()
        {
            MessageBox.Show("It works!");
        }

enter image description here

but sometime button seems not clickable or not fire click even. see below screenshot.

enter image description here

Message show already, but we do not see it in top of the worksheet. too many time click on the button it may happened. so if you do not see the dialog just open it from taskbar.

enter image description here
Reopen: Controls that are added at run time are not persisted when the document or workbook is saved and closed. The exact behavior is different for host controls and Windows Forms controls. In both cases, you can add code to your solution to re-create the controls when the user reopens the document.

           xlApp = new Excel.Application();
            string workbookPath = @"c:/Book.xlsx";
            xlWorkBook = xlApp.Workbooks.Open(workbookPath,
                    0, false, 5, "", "", false, Excel.XlPlatform.xlWindows, "",
                    true, false, 0, true, false, false);

            xlWorkSheet = (Excel.Worksheet)xlWorkBook.Worksheets.get_Item(1);

            xlApp.Visible = true;

            Microsoft.Office.Interop.Excel.OLEObject oleShape = xlWorkSheet.OLEObjects(1);
            Microsoft.Vbe.Interop.Forms.CommandButton button = oleShape.Object;
            button.Caption = "Custom Buttom" + i;

            button.Click += Button_Click;
            i++;

NB: Microsoft Excel 2013, project reference Microsoft office 15.0 object Library and VS 2022 work perfectly but Excel 2016 has this issue you are telling about. so I think this issue has come from
Microsoft Office specific version.

冷心人i 2025-01-23 02:02:31

如果你想让它计数点击尝试这个..

const btn = document.querySelector('.btn');
btn.onclick = Counter;
const clicks = document.querySelector('.clicks');
clicks.id = document.querySelector('clicks');

var a = 0;

function Counter() {
    a += 1;
    clicks.innerHTML = a;
}

const reset = document.querySelector('.reset');
reset.onclick = resetCounter;

function resetCounter() {
    a = 0;
    clicks.innerHTML = a;
}

if you want to make it count clicks try this..

const btn = document.querySelector('.btn');
btn.onclick = Counter;
const clicks = document.querySelector('.clicks');
clicks.id = document.querySelector('clicks');

var a = 0;

function Counter() {
    a += 1;
    clicks.innerHTML = a;
}

const reset = document.querySelector('.reset');
reset.onclick = resetCounter;

function resetCounter() {
    a = 0;
    clicks.innerHTML = a;
}

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文