代码之家  ›  专栏  ›  技术社区  ›  bob-the-destroyer

在运行时为hanlding事件定义的自定义/动态方法和委托,以告诉我触发了什么事件

  •  2
  • bob-the-destroyer  · 技术社区  · 14 年前

    除了对所有可能的事件处理程序进行硬编码之外,有没有一种方法可以在运行时动态地进行这项工作?

    我要做的是在运行时定义一个动态方法和一个动态委托来处理vb.net中可能发生的任何事件。我能告诉你一个事件被触发了,源对象也被触发了,但我不能告诉你 什么 事件已触发。

    我现在使用的方法可以正确处理我所知道的最基本的事件。但是,无法告诉我触发了什么特定事件。我的所有处理子(下面的部分示例是trigger_event())都知道 sender As Object, e As EventArgs . sender 是生成事件的对象,但它不会告诉我触发了什么。 EventArgs 可以扩展,但它永远不会包含事件的名称,因为这不是标准实践。

    下面是两个示例类subs,它目前能够处理大多数System.Windows.Forms事件,我知道在哪里可以将事件参数类型转换为标准事件参数类型。 Announce_Events() 用于命名我要侦听的事件,并在运行时模拟委托,当前将所有事件路由到 Triggered_Event()

    Public Sub Announce_Events(event_name As String)
    
    Dim obj_type = _a_specific_object.GetType()
    Dim obj_event_info = obj_type.GetEvent(event_name, BindingFlags.Instance OR BindingFlags.Public)
    
    Dim obj_event_delegate As [Delegate] = [Delegate].CreateDelegate(obj_event_info.EventHandlerType, Me, "Triggered_Event")
    obj_event_info.AddEventHandler(_a_specific_object, obj_event_delegate)
    obj_event_delegate = Nothing
    
    End Sub
    
    
    Private Sub Triggered_Event(sender As Object, e As EventArgs)
    
    ' Handle triggered event here
    
    End Sub
    

    我很难理解 dynamic methods 处理事件。也许在运行时我可以使用特定的函数措辞来定义我的处理方法?如何让sub-announced_events()通知触发的_event()触发了什么事件名称?

    注意:在我的例子中,所有委托和方法都必须动态定义,除非可以定义一个委托和方法来处理所有可能的事件。

    更新: 通过使用Markj和Hans Passant给出的任一解决方案来解决。这两个版本…

    Anon Sub:

    Public Sub Announce_Events(event_name As String)
    
    Dim obj_type = _a_specific_object.GetType()
    Dim obj_event_info = obj_type.GetEvent(event_name, BindingFlags.Instance OR BindingFlags.Public)
    Dim my_event_handler as EventHandler = Sub (sender As Object, e As Object)
        ' do something with sender, e, and event_name variables here '
        End Sub
    obj_event_info.AddEventHandler(_a_specific_object, my_event_handler)
    
    End Sub
    

    不需要定义触发的事件子级。但是,仍然需要一种方法来动态地将我的事件处理程序强制转换为obj事件处理程序info.eventhandlerType,否则只有当obj事件处理程序info.eventhandlerType可以狭义地转换为event handler时,它才能工作。

    工人对象:

    Public Sub Announce_Events(event_name As String)
    
    Dim obj_type = _a_specific_object.GetType()
    Dim obj_event_info = obj_type.GetEvent(event_name, BindingFlags.Instance OR BindingFlags.Public)
    Dim e_worker as new Event_Worker(event_name)
    Dim obj_event_delegate = [Delegate].CreateDelegate(obj_event_info.EventHandlerType, e_worker, "Triggered_Event")
    obj_event_info.AddEventHandler(_a_specific_object, obj_event_delegate)
    
    End Sub
    

    Event_Worker类有一个“Event Name”字段用于在事件激发时引用,并包含“Trigged_Event”子类,用于在传递“Event Name”时处理激发的事件。但是,“触发的事件”必须声明为接受“e”作为严格类型“eventargs”,或者至少是缩小转换。

    2 回复  |  直到 14 年前
        1
  •  1
  •   MarkJ    14 年前

    弗朗西斯科·巴勒纳的书 Programming Microsoft Visual Basic 2005 The Language 具有在Visual Studio 2005和2008中工作的技术。有一个通用的事件处理程序例程,它通过一个字符串来标识正在触发的事件。

    这是一个相当大的代码,我觉得没有作者的许可,我不能在这里发表这么长的摘录。这是一个描述,可能足以让你去。代码通过反射注册事件处理程序,如代码。它为每个事件创建一个小型工作对象的实例,以存储事件的名称。工作进程处理事件,并使用一个提供事件名称的附加参数调用其客户机。这听起来像很多物体,因此开销很大,但我相信它和 what the compiler does for you if you use lambda expressions 以及大大低于动态方法的。

    如果你 buy the book 有更完整的解释和完整的代码。

        2
  •  1
  •   Hans Passant    14 年前

    这里的问题当然是你只有 的事件处理程序 全部的 事件。是的,您需要为一个事件创建一个处理程序,这样您就可以拥有一个特定于事件的数据位,比如名称。到目前为止,最干净的方法是使用lambda表达式。但您需要子品种,这需要vb.net版本10(vs2010)。

    对于以前的版本,动态方法确实可以解决您的问题。尽管走起来很痛苦。首先在vb.net中编写代码,使用ildasm.exe找出需要生成什么IL。