如何在 .NET/C# 中通过反射引发事件?
我有一个第三方编辑器,它基本上包含一个文本框和一个按钮(DevExpress ButtonEdit 控件)。 我想让一个特定的击键(Alt + Down)模拟单击按钮。 为了避免一遍又一遍地编写此内容,我想创建一个通用的 KeyUp 事件处理程序来引发 ButtonClick 事件。 不幸的是,控件中似乎没有引发 ButtonClick 事件的方法,所以...
如何通过反射从外部函数引发事件?
I have a third-party editor that basically comprises a textbox and a button (the DevExpress ButtonEdit control). I want to make a particular keystroke (Alt + Down) emulate clicking the button. In order to avoid writing this over and over, I want to make a generic KeyUp event handler that will raise the ButtonClick event. Unfortunately, there doesn't seem to be a method in the control that raises the ButtonClick event, so...
How do I raise the event from an external function via reflection?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(9)
这是使用泛型的演示(省略错误检查):
Here's a demo using generics (error checks omitted):
一般来说,你不能。 将事件视为基本上成对的
AddHandler
/RemoveHandler
方法(因为这基本上就是它们的本质)。 如何实施它们取决于班级。 大多数 WinForms 控件使用EventHandlerList
作为他们的实现,但是如果你的代码开始获取私有字段和密钥,它将会非常脆弱。ButtonEdit
控件是否公开了您可以调用的OnClick
方法?脚注:实际上,事件可以具有“raise”成员,因此
EventInfo.GetRaiseMethod
。 然而,C# 从未填充过它,而且我也不认为它存在于一般框架中。In general, you can't. Think of events as basically pairs of
AddHandler
/RemoveHandler
methods (as that's basically what what they are). How they're implemented is up to the class. Most WinForms controls useEventHandlerList
as their implementation, but your code will be very brittle if it starts fetching private fields and keys.Does the
ButtonEdit
control expose anOnClick
method which you could call?Footnote: Actually, events can have "raise" members, hence
EventInfo.GetRaiseMethod
. However, this is never populated by C# and I don't believe it's in the framework in general, either.您通常不能引发其他班级事件。 事件实际上存储为私有委托字段,加上两个访问器(add_event 和remove_event)。
要通过反射来完成此操作,您只需找到私有委托字段,获取它,然后调用它。
You can't normally raise another classes events. Events are really stored as a private delegate field, plus two accessors (add_event and remove_event).
To do it via reflection, you simply need to find the private delegate field, get it, then invoke it.
我编写了一个类扩展,它实现了 INotifyPropertyChanged 以注入 RaisePropertyChange方法,所以我可以像这样使用它:
无需在任何基类中实现该方法。 对于我的使用来说,它很慢,但也许源代码可以帮助某人。
所以这里是:
我删除了原始代码的某些部分,因此扩展应该按原样工作,而不引用我的库的其他部分。 但它还没有真正经过测试。
PS 部分代码是从别人那里借来的。 真可惜,我忘记了从哪里得到它。 :(
I wrote an extension to classes, which implements INotifyPropertyChanged to inject the RaisePropertyChange<T> method, so I can use it like this:
without implementing the method in any base class. For my usage it was to slow, but maybe the source code can help someone.
So here it is:
I removed some parts of the original code, so the extension should work as is, without references to other parts of my library. But it's not really tested.
P.S. Some parts of the code was borrowed from someone else. Shame on me, that I forgot from where I got it. :(
看来 Wiebe Cnossen 的接受的答案中的代码可以简化为:
It seems that the code from the accepted answer by Wiebe Cnossen could be simplified to this:
来自提高通过反射的事件,尽管我认为答案在 VB.NET ,也就是说,在此之前的两篇文章将为您提供通用方法(例如,我会在 VB.NET 文章中寻找引用不在同一类中的类型的灵感):
From Raising an event via reflection, although I think the answer in VB.NET, that is, two posts ahead of this one will provide you with the generic approach (for example, I'd look to the VB.NET one for inspiration on referencing a type not in the same class):
事实证明,我可以做到这一点,但没有意识到:
但如果我做不到,我就必须深入研究源代码并找到引发事件的方法。
谢谢大家的帮助。
As it turns out, I could do this and didn't realize it:
But if I couldn't I would've have to delve into the source code and find the method that raises the event.
Thanks for the help, all.
如果您知道该控件是一个按钮,则可以调用其
PerformClick()
方法。 对于其他事件(如 OnEnter、OnExit)我也有类似的问题。 如果我不想为每个控件类型派生新类型,我就无法引发这些事件。If you know that the control is a button you can call its
PerformClick()
method. I have similar problem for other events likeOnEnter
,OnExit
. I can't raise those events if I don't want to derive a new type for each control type.对一些现有答案和评论的进一步细化。
这还考虑到委托字段可以在继承类上定义。
A further refinement on some of the existing answers and comments.
This also takes into account that the delegate field may be defined on an inherited class.