将EventHandler传递给方法

时间:2017-10-15 21:50:09

标签: c#

我正在尝试将eventHandler传递给方法。 在我的方法中,我将使用不同类型的eventHandlers。即KeyDownEventHandler,ClickEventHandler等。

可以这样做吗?

@Enigmativity

这是完整的测试代码。就像我说我试图传递EventHandlers名称。正如你在这里看到的那样。但当我得到每个它的正文而不是真正的事件处理程序。在foreach循环中,您将看到它应该删除或添加事件(订阅或取消订阅)的位置。当我确实得到它的一半工作。 unsubscribed remove删除事件处理程序不起作用。它应该工作的方式是我在form1事件+ =中有6个订阅事件,对于textbox1到textchange来命中。当它发生时,我点击它进入DisableEvents方法它会抛出foreach然后当它完成它再次返回到textbox1_textbox1_textchange。 6次。我希望DisableEvents删除其他订阅的。取决于最后一个变量true或false将设置或删除它。让我知道,如果有任何问题,我可以帮助解决这个问题。 @Enigmativity 这是描述我的问题的最佳方式。 form1设置subscribe(+ =)。然后在textBox1_textChanged事件中我只添加了一行textBox1.TextChanged - = null;而已。当我运行代码6时,订阅被设置,当我单击文本框并键入任何一个char时,textBox1_Changed命中。我认为 - = null应该清除所有订阅,textbox1_Changed不会再次上升,直到我订阅它。我哪里错了?想要一个方法,所以我可以传递参数。但我想这不可能完成或者可以。我继续阅读。感谢

    public Form1()
    {
        InitializeComponent();

        //Setup the subscribed here         

        textBox1.TextChanged += textBox1_TextChanged;
        textBox1.TextChanged += textBox1_TextChanged;
        textBox1.TextChanged += textBox1_TextChanged;
        textBox1.TextChanged += textBox1_TextChanged;
        textBox1.TextChanged += textBox1_TextChanged;
        textBox1.TextChanged += textBox1_TextChanged;
    }

    private void textBox1_TextChanged(object sender, EventArgs e)
    {
        DisableEvents(textBox1, "TextChanged", textBox1_TextChanged, false);
    }

    private static Delegate[] DisableEvents(object target, string eventName, EventHandler eventHandlerName, bool add)
    {
        FieldInfo fieldInfo = typeof(Control).GetField("Event" + eventName, BindingFlags.NonPublic | BindingFlags.Static);

        PropertyInfo propertyInfo = target.GetType().GetProperty("Events", BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance);

        EventHandlerList eventHandlerList = (EventHandlerList)propertyInfo.GetValue(target, null) as EventHandlerList;

        object eventKey = fieldInfo.GetValue(target);

        var _eventHandler = eventHandlerList[eventKey] as Delegate;

        if (_eventHandler == null)
            return null;

        Delegate[] invocationList = _eventHandler.GetInvocationList();

        foreach (eventHandlerName item in invocationList)
        {
            if (add)
            {
                target.GetType().GetEvent(eventName).AddEventHandler(target, item);
            }
            else
            {
                target.GetType().GetEvent(eventName).RemoveEventHandler(target, item);
            }
        }
        return invocationList;
    }



//here is the example.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace MyEventsExample
{
public partial class Form1 : DevExpress.XtraEditors.XtraForm
{
    public Form1()
    {
        InitializeComponent();
        //Subscribe 8 times
        for (int c = 0; c < 7; c++)
        {
            textBox1.KeyDown += textBox1_KeyDown;

            MessageBox.Show("Events added at Start # : " + c.ToString());
        }

        button1.Click += button1_Click;
    }

    int a;
    int b;
    int c;

    private void textBox1_KeyDown(object sender, KeyEventArgs e)
    {
        //This should take the subscribed += and remove them -=.

        EventDescriptor edTypeDescriptor.GetEvents(textBox1).Find     ("KeyDown", true);

        if (ed != null)
        {
            for (int i = 0; i < ed.Attributes.Count; i++)
            {
                ed.RemoveEventHandler(textBox1, Delegate.CreateDelegate(typeof(KeyEventHandler), this, "textBox1_KeyDown"));
            }
        }

        //after the above is done this event should not work at all any more unless i subscribe to it again
        //But it keeps hitting the event the total of the subscried time in this case 8 times it enters in.                                                  
//when i make my method ill need a way to pass the typeof in this            case       its    the KeyEWvenHandler.

        a++;

        MessageBox.Show("Done " + a);
    }
    private void button1_Click(object sender, EventArgs e)
    {
        //Lets do it again
        //Subscribe 8 times
        for (int b = 0; b < 7; b++)
        {
            textBox1.KeyDown += textBox1_KeyDown;

            MessageBox.Show("Event Button Add  # : " + b.ToString());
        }
    }
}

} 生病需要将textBox1中的代码转换为一个方法,像textbox一样传递控件类型,像textbox_KeyDown一样传递事件动作,但最重要的是事件处理程序,如textBox1_KeyDown事件中的KeyEventHandler。但最重要的是清除了我传递方法的所有事件。

1 个答案:

答案 0 :(得分:1)

事件处理程序和事件之间存在差异。

事件处理程序只是一个委托。它可以毫无问题地传播。

拿这段代码:

Action foo = () => Console.WriteLine("1");

foo += () => Console.WriteLine("2");

foo();

写出1&amp; <{1}}被调用时。

我可以将2作为参数传递给任何方法。问题是委托是不可变的引用类型。这意味着如果您修改委托,例如下面的Action foo示例,那么您已经创建了一个新委托,并且更改未反映在bar += () => Console.WriteLine("3")中。当您进行更改时,它们不再是对同一对象的引用。

foo

因此,如果我将该代码添加到原始代码,则会输出Action bar = foo; bar += () => Console.WriteLine("3"); foo(); bar(); 121212

3代表添加新处理程序时,原始foo未被修改。

如果您尝试修改自己引用的副本,则无法影响原始代理。

另一方面,事件根本无法传递。这就是编译器的工作方式。只要您具有对包含事件的原始对象的引用,您就只能将处理程序附加到事件并将其分离。

你必须使用棘手的反射代码才能使传递事件成为可能,但这绝对不是一种直接的方法。

我怀疑还有另一个选项适合你。

我建议您使用Microsoft的Reactive Framework。它就像类固醇的事件库。

你可以做这件事:

bar

您通过致电TextBox textBox = new TextBox(); IObservable<EventPattern<TextBox, KeyEventArgs>> keyDowns = Observable .FromEventPattern<TextBox, KeyEventArgs>( textBox, "KeyDown"); IDisposable textBoxKeyDownsSubscription = keyDowns .Subscribe(ep => { // Use `ep.Sender` & `ep.EventArgs` here // Both are strongly-typed }); 来附加活动,并通过致电.Subscribe(...)分离。

这种方法的优势在于,您现在可以将textBoxKeyDownsSubscription.Dispose()作为该语言的一等公民传递,并附加和分离订阅者,而不保留对原始对象的引用,也不进行任何反映。 / p>

此外,您可以使用标准的LINQ操作对此对象进行查询。现在这成为可能:

IObservable<EventPattern<TextBox, KeyEventArgs>>

查询TextBox textBox = new TextBox(); IObservable<EventPattern<TextBox, KeyEventArgs>> keyDowns = Observable .FromEventPattern<TextBox, KeyEventArgs>( textBox, "KeyDown"); bool enabled = true; IObservable<Keys> onlyAOrBWhenEnabled = from kd in keyDowns where kd.EventArgs.KeyCode == Keys.A || kd.EventArgs.KeyCode == Keys.B where enabled == true select kd.EventArgs.KeyCode; IDisposable onlyAOrBWhenEnabledSubscription = onlyAOrBWhenEnabled .Subscribe(keyCode => { // Use `keyCode` here }); 对原始事件执行逻辑,仅在onlyAOrBWhenEnabled时返回AB的键。如果您要禁用该事件,则只需设置enabled == true

我不清楚你打算做什么enabled = false,但如果你能澄清一下,我可以提供一个更好的例子来说明如何使用它。

Just NuGet&#34; System.Reactive&#34; &安培; &#34; System.Reactive.Windows.Forms&#34;得到你需要的东西。