在 Excel 事件 BeforeSave 上显示 Form2

Show Form2 on Excel event BeforeSave

在 Visual Studio 2017 年,我正在创建一个带有 Form1 的 Windows 表单应用程序,用户可以在其中选择一个打开的 Excel 工作簿来收听其 BeforeSave 事件。

保存该工作簿后,程序会检测到它,然后从工作表中收集一些特定数据并使用该数据打开 Form2

我遇到的问题是,当我在 BeforeSave 事件上加载 Form2 时,它的控件(如标签、按钮、文本框等)无法正确显示。它们看起来像带有背景颜色的框。

这是我的代码,并更改为重要的部分:

' Reference:
' Microsoft Excel 15.0 Object Library
Imports Microsoft.Office.Interop
Public Class Form1
    Private xlApp As Excel.Application
    Public Shared WithEvents xlBook As Excel.Workbook
    Private Shared Sub Workbook_BeforeSave(SaveAsUI As Boolean, ByRef Cancel As Boolean) Handles xlBook.BeforeSave
        Form2.Show()
        'Form1.Close()
    End Sub
    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles Me.Load
        Try
            xlApp = Runtime.InteropServices.Marshal.GetActiveObject("Excel.Application")
            xlBook = xlApp.Workbooks(1)
        Catch
            MsgBox("Excel isn't opened.")
            Close()
        End Try
    End Sub
End Class

编辑: 使用 Application.Run(Form2) 有效(不知道为什么)但是我也无法用 Form1.Close() 关闭 Form1 .

BeforeSave 事件 与其他 Interop.Excel 事件一样 是在不同的线程上引发的。因此,您不能直接从它访问 GUI 线程。为了访问 GUI 线程(例如,访问表单控件、在主线程上创建表单等),您需要使用委托调用 Invoke 方法。

Form2.Show() 替换为以下内容可以解决问题:

Invoke(Sub() Form2.Show())

但是,您应该为要加载的表单创建一个 new 实例。因此,您应该使用如下内容代替上一行:

Private Sub Workbook_BeforeSave(SaveAsUI As Boolean,
                                ByRef Cancel As Boolean) Handles xlBook.BeforeSave
    Invoke(Sub()
               Dim frm As New Form2
               frm.Show()
           End Sub)
End Sub

要了解有关 WinForms 线程安全调用的更多信息,请查看参考资料中的第一篇文章。


参考文献: