按名称删除事件

时间:2014-03-24 12:06:58

标签: vb.net events handler removeall

我想使用VisualBasic .Net从WinForms控件中删除特定的处理程序。

例如:

我有一个Windows.Forms.ToolStripButton,注册了Click-Event以保存数据。

现在我需要从Button中删除此事件,但我无法访问已注册的Event-Method !!我知道哪个Handle被使用了。在我的情况下“点击”

为了更好地理解:我必须为GridView编写扩展。当选择多行时,我必须集成所选行的批量编辑。为此,我需要为保存按钮注册一个新的点击事件并删除旧的。但我没有访问事件处理程序的地址。我只有注册事件的按钮

这是我到目前为止所尝试的:

Dim btnSaveEventInfo = btnSave.GetType.GetEvent("Click")
Dim method = Activator.CreateInstance(btnSaveEventInfo.GetType, True)

RemoveHandler btnSave.Click, method

抛出InvalidCastException

有人有任何想法吗?

Gr33tz gangfish

1 个答案:

答案 0 :(得分:2)

哇。这比我想象的要难得多。有可能做到这一点,但我会警告你,这真是一团糟。最终,您需要做的是获取事件的Delegate对象。一旦你有了这个,删除事件处理程序很容易,因为你可以这样做:

Dim d As [Delegate] = ' ... (we'll figure this out later)
For Each handler As [Delegate] In d.GetInvocationList()
    RemoveHandler btnSave.Click, DirectCast(handler, EventHandler)
Next

然而,获得该活动的代表特别困难。反射使得为任何所需事件获取EventInfo对象变得容易,但它没有提供获取该事件的委托的简单方法。从技术上讲,肯定没有办法总是获得委托,因为事件会私有地封装他们的委托,并且可以以任何自定义方式实现。但是,由于大多数事件都是在" normal"通过反射可以使私有代理隐藏在对象中。当然,如果微软决定改变正常情况,所有这一切都会破裂。它编制事件的方式,但由于这是你获得的最佳选择,你会被它困住。

为了进一步复杂化,WinForm控件的事件处理程序以自定义方式实现(虽然彼此一致),以便获取控件事件的委托更复杂。在this page of Bob Powell's blog上对所有这些内容进行了精彩的记录。这里重复所有信息对我来说太冗长了,但是我用它来组建一个如何解决你的特定情况的VB.NET示例:

Dim currType As Type = btnSave.GetType()
Dim eventFieldInfo As FieldInfo = Nothing
Do
    eventFieldInfo = currType.GetField("EventClick", BindingFlags.Static Or BindingFlags.Instance Or BindingFlags.NonPublic)
    If eventFieldInfo Is Nothing Then
        currType = currType.BaseType
    End If
Loop While eventFieldInfo Is Nothing

Dim ehl As EventHandlerList = DirectCast(btnSave.GetType().GetProperty("Events", BindingFlags.Instance Or BindingFlags.NonPublic Or BindingFlags.FlattenHierarchy).GetValue(btnSave), EventHandlerList)
Dim d As [Delegate] = ehl(eventFieldInfo.GetValue(btnSave))

For Each handler As EventHandler In d.GetInvocationList()
    RemoveHandler btnSave.Click, handler
Next

请参阅上面的链接,了解其原因和方法。但是,正如我所说,这非常难看,可能会在未来的.NET版本中出现问题。因此,如果您还有其他方法可以做到这一点,那么最好使用这些替代方案。例如,如果您可以控制添加事件处理程序的代码,则可以保留对该委托的单独引用,以便稍后将其删除,例如:

Dim myClickHandler As EventHandler = AddressOf btnSave_Click
AddHandler btnSave.Click, myClickHandler

' ...

RemoveHandler btnSave.Click, myClickHandler