如何在C#中手动调用事件?
我有一个USerControll,其中有一个文本框。我在表单中使用usercontrol,当有人按下文本框上的enter键时,我想做一些事情。我怎么做?如何在C#中手动调用事件?,c#,winforms,visual-studio-2010,C#,Winforms,Visual Studio 2010,我有一个USerControll,其中有一个文本框。我在表单中使用usercontrol,当有人按下文本框上的enter键时,我想做一些事情。我怎么做? 如果您告诉我如何手动调用事件,我可以在textbox.keydown中调用usercontrol.keydown。首先,只能从声明事件的控件内的代码引发事件。因此,您的用户控件必须声明自定义事件KeyDown才能引发它。例如,您不能在用户控件包含的文本框上提高KeyDown。但是,您可以声明自己的KeyDown,并将处理程序附加到文本框的Key
如果您告诉我如何手动调用事件,我可以在textbox.keydown中调用usercontrol.keydown。首先,只能从声明事件的控件内的代码引发事件。因此,您的用户控件必须声明自定义事件KeyDown才能引发它。例如,您不能在用户控件包含的文本框上提高KeyDown。但是,您可以声明自己的KeyDown,并将处理程序附加到文本框的KeyDown,该处理程序将引发您自己的KeyDown 鉴于此限制,引发事件很容易:
public delegate void MyEventHandler(object sender, MyEventArgs e)
public event MyEventHandler MyEvent;
public void RaisesMyEvent()
{
...
if(MyEvent != null) //required in C# to ensure a handler is attached
MyEvent(this, new MyEventArgs(/*any info you want handlers to have*/));
}
提出一个事件看起来很像一种方法,因为本质上这就是你正在做的;您正在调用一个或多个在事件幕后分配给多播代理的方法代理。可以将其视为将一个方法分配给一个普通的命名委托(例如,如果您在定义中省略了“event”关键字),并从代码内部调用它。真实事件与真实事件之间的唯一区别在于,一个事件可以附加多个处理程序委托,并在引发时调用所有这些委托。您所描述的称为事件冒泡。下面是一个例子:
<%@ Control Language="C#" AutoEventWireup="true" CodeBehind="MyUserControl.ascx.cs" Inherits="MyUserControl" %>
<asp:TextBox ID="TextBox1" runat="server" OnTextChanged="TextBox1_TextChanged" />
通常情况下,事件调用被包装在一个名为“On[EventName]”的方法中,该方法验证delgate是否有一个或多个目标(事件不为null),然后使用发送方和任何适用的参数调用它……因此,类似这样的典型模式是:
public event EventHandler SomethingHappened;
protected void OnSomethingHappend(EventArgs e)
{
if (SomethingHappened != null)
SomethingHappened(this, e);
}
任何需要引发该事件的事件都会调用该方法(假定其可访问)
如果您只是想传递事件,那么作为一个UserControl,您可能只需要调用基本的“On[event]”方法,该方法很可能是公开的。您也可以连接事件处理程序,将子控件中的事件作为父控件的事件直接传递…以便txtFoo.KeyPress仅调用父控件的OnKeyPress方法。如果您使用WPF,则可以使用RaiseEvent: 但这对于你想做的事情来说是错误的 你应该把这件事搞砸
class MyControl : UserControl {
public KeyDownEventHandler KeyDown;
private void OnTextBoxKeyDown(object sender, EventArgs e){ KeyDown.Invoke(sender, e); }
}
然后从你的表格中听KeyDown。请原谅在命名各种元素/事件时出现的错误。我正在为这个问题寻找答案 就这么做吧 例:
//this is the call to trigger the event:
**lst_ListaDirectorios_SelectedIndexChanged(this, new EventArgs());**
//do that if you have the method signature in the same class as I do. (something like this below)
private void lst_ListaDirectorios_SelectedIndexChanged(object sender, EventArgs e)
{
//do something
}
我希望这对您有用。如果您确实需要手动调用事件,您可以获取支持代理,它通常是私有的。使用.NET反编译器(如ILSPY)定位事件的备份字段,然后使用反射获取备份委托 示例:从
BackgroundWorker
获取事件DoWork
:
在ILSpy中反编译BackgroundWorker
类,您会看到:
public event DoWorkEventHandler DoWork
{
add
{
base.Events.AddHandler(doWorkKey, value);
}
remove
{
base.Events.RemoveHandler(doWorkKey, value);
}
}
因此,您需要找到事件
成员和doWorkKey
字段作为键
事件
是在类组件
中声明的事件句柄列表
(公共类)
doWorkKey
是在类BackgroundWorker
中声明的静态字段
然后使用反射获取代理:
PropertyInfo property = backgroundWorker.GetType().GetProperty("Events", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy);
EventHandlerList eventHandlerList = (EventHandlerList)property.GetValue(backgroundWorker, null);
FieldInfo doWorkField = backgroundWorker.GetType().GetField("doWorkKey", BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.FlattenHierarchy);
object doWorkKey = doWorkField.GetValue(null);
DoWorkEventHandler doWork = (DoWorkEventHandler)eventHandlerList[doWorkKey];
现在您有了DoWork
事件的委托,可以调用它
同样的方法也适用于其他控件
请注意,使用反射获取私有字段可能会在代码的任何新版本出现时中断。因此,您希望从TextBox.KeyDown事件处理程序中引发UserControl.KeyDown事件,对吗?因此,在用户实际按下按键时响应事件对于您的场景来说是不够的?我想我在你的场景中遗漏了一些东西。@saeed-原则上解决方案是相同的,但这是针对ASP.NET还是WinForms的?@RQDQ:我不明白你遗漏了什么。我只是想澄清一下,因为我可能误解了这个问题。您是专门寻找“回车”还是试图通过文本框捕获提交?不幸的是,此代码不是线程安全的。您需要创建
MyEvent
的本地副本,以防止另一个线程同时删除if
和事件调用之间的所有事件处理程序时出现NullReferenceExceptions
。。。。或者在计算if之前锁定(MyEvent()),然后释放它。问题只是关于举办一个活动,这就是我的回答;如果他随意地连接和分离处理程序,这表明他对事件有更深入的了解,不必问这个问题。原则上你是对的,但这不是我的意思:在本地复制事件是一种牢固确立的最佳实践。任何事件引发代码都不应该在没有它的情况下编写,即使是作为一个示例也不应该(因为如果您不希望出现多线程问题,您就不会想到它)。随意附加事件并不是用户控件的代码可以控制的——这取决于用户。作为一个可重用的代码,用户控制代码应该尽可能地健壮。嗯,这是一个教条,但在这里几乎不相关。一个控件只有4个成员,这些成员被记录为可从另一个线程使用(InvokeRequired等)。即使是MSFT也不能始终如一地做到这一点,例如NumericUpDown。但是任何多播代理都不能连接多个代理吗?那么,一个活动有什么不同呢?
//this is the call to trigger the event:
**lst_ListaDirectorios_SelectedIndexChanged(this, new EventArgs());**
//do that if you have the method signature in the same class as I do. (something like this below)
private void lst_ListaDirectorios_SelectedIndexChanged(object sender, EventArgs e)
{
//do something
}
public event DoWorkEventHandler DoWork
{
add
{
base.Events.AddHandler(doWorkKey, value);
}
remove
{
base.Events.RemoveHandler(doWorkKey, value);
}
}
PropertyInfo property = backgroundWorker.GetType().GetProperty("Events", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy);
EventHandlerList eventHandlerList = (EventHandlerList)property.GetValue(backgroundWorker, null);
FieldInfo doWorkField = backgroundWorker.GetType().GetField("doWorkKey", BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.FlattenHierarchy);
object doWorkKey = doWorkField.GetValue(null);
DoWorkEventHandler doWork = (DoWorkEventHandler)eventHandlerList[doWorkKey];