2014-03-24 41 views
1

我想从WinForms控件中用VisualBasic.Net移除特定的处理程序。按名称移除事件

例如:

我有一个Windows.Forms.ToolStripButton与点击,事件记录来保存数据。

现在我需要从按钮中删除此事件,但我无法访问注册的事件方法!我只能知道使用哪个Handle。在我的情况“点击”

为了更好的理解:我必须编写一个GridView扩展。当选择多行时,我必须整合所选行的批量编辑。为此,我需要为savebutton注册一个新的点击事件并删除旧的。但是我对事件处理程序的地址没有访问权限。我只有与注册事件

按钮这是我试过到目前为止:

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

RemoveHandler btnSave.Click, method 

这引发InvalidCastException

任何人任何想法?

Gr33tz gangfish

+0

该方法如何被注册为事件处理程序首先? – Crono

+1

可能的重复[是否有可能从一个控件“窃取”事件处理程序并将其提供给另一个?](http://stackoverflow.com/questions/293007/is-it-possible-to-steal-an-事件处理程序从一个控制,并给它它到另一个) –

+0

Methdo注册处理函数:私人小组btnSave_Click(发件人为对象,e作为EventArgs)处理btnSave.Click SaveChanges() End Sub – gangfish

回答

2

哇。这比我预料的要难得多。这是可能的,但我会警告你,这真是一团糟。最终,你需要做的是获得事件的对象。一旦你的,移除事件处理很容易,因为你可以做这样的事情:

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对象,但它并不提供获取该事件委托的简单方法。从技术上讲,当然,总是无法获得委托,因为事件私自封装了它们的委托,并且可以以任何自定义的方式实现。但是,由于大多数事件都是以“正常”方式实现的,因此可以通过反射来将私人代理隐藏在对象中。当然,如果微软决定改变编写事件的“正常”方式,那么所有这些都会中断,但由于这是您获得的最佳选择,因此您一直坚持使用它。

更复杂的是,对于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 
+1

只要EventHandlerList,当我看到你已经制定了一篇文章:) +1 – MrPaulch

+0

@MrPaulch很好的工作!我很高兴知道我不是唯一一个被吸入这个兔子洞的人。 –

+0

thx很多。从来没有想到这一点。 – gangfish