WinForms: How to programmatically fire an event ha

2020-02-23 07:19发布

I want to programmatically invoke an event handler for a control. For example:

DateTimePicker dtpLastConsummated;

I want to trigger the TextChanged event handler for the dtpLastConsummated, how can i do it?

In other languages I would call something akin to:

dtpLastConsummated.TextChanged(this, new EventArgs());

but in .NET you can have multiple event handlers:

dtpLastConsummated.Click +=new EventHandler(dtpLastConsummated_TextChanged);
dtpLastConsummated.Click +=new EventHandler(dtpLastConsummated_AnotherHandler);
dtpLastConsummated.Click +=new EventHandler(dtpLastConsummated_MoreHandlers);
...
dtpLastConsummated.Click +=new EventHandler(dtpLastConsummated_Nminus1);

so you need a way to trigger all the attached event handlers.


Answer

The following code will fire the event:

Toolkit.FireEvent(dtpLastConsummated, "TextChanged", new EventArgs());

And here's the code of the static toolkit function:

/// <summary>
/// Programatically fire an event handler of an object
/// </summary>
/// <param name="targetObject"></param>
/// <param name="eventName"></param>
/// <param name="e"></param>
public static void FireEvent(Object targetObject, string eventName, EventArgs e)
{
   /*
    * By convention event handlers are internally called by a protected
    * method called OnEventName
    * e.g.
    *     public event TextChanged
    * is triggered by
    *     protected void OnTextChanged
    * 
    * If the object didn't create an OnXxxx protected method,
    * then you're screwed. But your alternative was over override
    * the method and call it - so you'd be screwed the other way too.
    */

   //Event thrower method name //e.g. OnTextChanged
   String methodName = "On" + eventName;

   MethodInfo mi = targetObject.GetType().GetMethod(
         methodName, 
         BindingFlags.Instance | BindingFlags.NonPublic);

   if (mi == null)
      throw new ArgumentException("Cannot find event thrower named "+methodName);

   mi.Invoke(targetObject, new object[] { e });
}

Note: I'm not creating a subclass of every control in the .NET framework, and every 3rd party control, and convincing an enterprise worth of developers to retrofit every form to use my custom controls.

4条回答
虎瘦雄心在
2楼-- · 2020-02-23 07:59

You can inherit from that class and create a new method that calls the protected OnSomeEvent() method.

class MyButton : Button
{
    public void CauseClick()
    {
        this.OnClick();
    }
}

As Matt pointed out, you can use PerformClick() for this specific example. However, most events don't have corresponding public functions to trigger them.

查看更多
姐就是有狂的资本
3楼-- · 2020-02-23 08:04

Following code helped me to fire event

ddlTopic_SelectedIndexChanged(this, new EventArgs());

Actual Event

private void ddlTopic_SelectedIndexChanged(object sender, EventArgs e)
{
   // do something
}
查看更多
\"骚年 ilove
4楼-- · 2020-02-23 08:05

Button in Windows Forms is a special case, because it has a PerformClick method to do exactly what you're talking about. For other events in other controls, though, there's really nothing similar.

查看更多
▲ chillily
5楼-- · 2020-02-23 08:11

3 suggestions to fire the TextChanged Event:

Manually change the text:

        string s = dateTimePicker1.Text;
        dateTimePicker1.Text = String.Empty;
        dateTimePicker1.Text = s;

or

Inherit from DateTimePicker and create a new method that exposes / calls DateTimePicker's protected OnTextChanged

public class MyDateTimePicker : DateTimePicker
{
    public void OnTextChanged(EventArgs e)
    {
        base.OnTextChanged(e);
    }
}

or

If you don't like OOP and want to break encapsulation, you can access the protected OnTextChanged method through reflection:

        MethodInfo onTextChanged = dateTimePicker1.GetType().GetMethod("OnTextChanged", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
        onTextChanged.Invoke(dateTimePicker1, new object[] { new EventArgs() });
查看更多
登录 后发表回答