在 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 线程安全调用的更多信息,请查看参考资料中的第一篇文章。
参考文献:
- How to: Make Thread-Safe Calls to Windows Forms Controls
- Why is there a default instance of every form in VB.Net?
在 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 线程安全调用的更多信息,请查看参考资料中的第一篇文章。
参考文献:
- How to: Make Thread-Safe Calls to Windows Forms Controls
- Why is there a default instance of every form in VB.Net?