将事件处理程序附加到从运行时加载的 dll 创建的表单

问题描述 投票:0回答:1

我正在寻找一种方法来处理关闭事件并获取一个返回参数。
我无法改变

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 
vb.net winforms dll activator
1个回答
1
投票

举个例子,假设您发布的代码与真实场景相符。

当目标事件及其提供者的类型在当前程序集中未知时,不能使用

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
© www.soinside.com 2019 - 2024. All rights reserved.