我正在寻找一种方法来处理关闭事件并获取一个返回参数。
我无法改变
WinFormApp.dll
的运行方式。
Private Sub ShowWinFormApp() Handles Button1.Click
' launching new WinForm app from within another app
Dim InvTrack As System.Reflection.Assembly = System.Reflection.Assembly.Load(File.ReadAllBytes("\\NetworkPath\WinFormApp.dll"))
Dim oType As System.Type
Dim pControl As System.Object
Dim Params As New List(Of Object)
Params.Add(Param1)
Params.Add(Param2)
oType = InvTrack.GetType("WinFormApp.FrmMain")
pControl = Activator.CreateInstance(oType, Params)
'here i'd like to add handler to catch my event
AddHandler pControl.ImDone, AddressOf ReLaunch
'this not working, saying that Element `ImDone` is not an event of element `Object`
Application.Run(pControl)
End Sub
在
WinFormApp
我尝试过这样的:
Public Class FrmMain
Public Event ImDone As EventHandler(Of ImDoneEventArgs)
Public Sub Test() Handles Button1.Click
RaiseEvent ImDone (Me, New ImDoneEventArgs With {.RetVal = 54})
Application.Exit()
End Sub
Public Class ImDoneEventArgs
Inherits EventArgs
Public Property RetVal As Integer
End Class
End class
举个例子,假设您发布的代码与真实场景相符。
当目标事件及其提供者的类型在当前程序集中未知时,不能使用
AddHandler
。 Activator.CreateInstance()
返回仅公开其基本方法的 object
类型。
您可以将对象转换为它的基类,即 Form 类。两个程序集都知道此类型。当然,基类不公开自定义事件,但您可以使用调用其
ShowDialog()
方法来呈现表单。
如果消息循环已在运行,则无法直接调用
Application.Run()
。但您不需要这样做,ShowDialog()
已经以兼容的方式为您做到了。
要为自定义事件创建事件处理程序,您可以再次使用 Reflection 来获取相关的 EventInfo,将 EventHandler 关联到引发事件时调用的方法,然后调用 Delegate.CreateDelegate() 传递[EventInfo].EventHandlerType 和处理程序的方法 Target,以生成兼容的委托。
现在,您可以将事件处理程序添加到
FrmMain
对象实例的事件中,调用 [EventInfo].AddEventHandler(),传递提供事件的对象(FrmMain
对象)和事件委托:
Dim FrmMain As Form = Nothing
Dim FrmMainEvent As EventInfo = Nothing
Dim _EventDelegate As [Delegate] = Nothing
Dim _EventHandler As EventHandler(Of EventArgs) = Sub(s, e) ReLaunch(s, e)
Dim asm As Assembly = Assembly.Load(File.ReadAllBytes("WinFormApp.dll"))
Dim formType = asm.GetType("WinFormApp.FrmMain")
If formType Is Nothing Then Throw New Exception("FrmMain Type not found")
Dim instance = Activator.CreateInstance(formType, {Param1, Param2})
If instance IsNot Nothing Then
FrmMain = DirectCast(instance, Form)
FrmMainEvent = instance.GetType().GetEvent("ImDone")
If FrmMainEvent IsNot Nothing Then
_EventDelegate = [Delegate].CreateDelegate(
FrmMainEvent.EventHandlerType, _EventHandler.Target, _EventHandler.Method
)
FrmMainEvent.AddEventHandler(instance, _EventDelegate)
End If
FrmMain.ShowDialog()
End If
请注意,您还可以使用操作委托类型,这可以稍微简化您的代码。
当事件引发时,指定的委托被调用。
此时您应该删除事件处理程序,调用 [EventInfo].RemoveEventHandler(),传递提供事件的对象实例(您生成的
FrmMain
实例)以及与事件关联的委托.
EventArgs 对象也是一个自定义类型,因此您可以再次通过反射检索其属性的值:
Public Sub ReLaunch(sender As Object, e As EventArgs)
If FrmMainEvent IsNot Nothing AndAlso _EventDelegate IsNot Nothing Then
FrmMainEvent.RemoveEventHandler(FrmMain, _EventDelegate)
End If
Debug.WriteLine(e.GetType().GetProperty("RetVal").GetValue(e))
_EventDelegate = Nothing
FrmMainEvent = Nothing
FrmMain = Nothing
End Sub