如何将事件传递给方法然后订阅它?

时间:2012-11-18 22:29:50

标签: c# .net events delegates

事件处理程序

public void DeliverEvent(object sender, EventArgs e)
{

}

#1:此作品

public void StartListening(Button source)
{
    source.Click += DeliverEvent;
}

#2:这也是......

public void StartListening(EventHandler eventHandler)
{
    eventHandler += DeliverEvent;
}

但是在#2中,你无法调用该方法,因为如果你尝试这样的话:

StartListening(button.Click);

您收到此错误:

The event 'System.Windows.Forms.Control.Click' can only appear on the left hand side of += or -=

有没有解决这个错误的方法?我希望能够将事件而非事件的对象传递给StartListening方法。

4 个答案:

答案 0 :(得分:1)

您不能将事件作为参数传递,因为它不是委托类型的对象。事件是一对两种方法 - addremove

即。按钮类的Click事件实际上看起来像

public void add_Click(EventHandler value) 
{
   // combine delegate
}

public void remove_Click(EventHandler value) 
{
   // remove delegate
}

如果要订阅事件,则应传递整个对象,然后为该特定事件调用add方法(使用+=语法)。

答案 1 :(得分:1)

您正在与代表混合活动。你应该阅读Jon Skeet的this文章,它将解释两者之间的差异。

第二个选项不起作用的原因是因为该方法需要一个符合EventHandler签名的委托参数。Button.Click指的是事件而不是委托。事件只是封装代表。

我不确定你的尝试是做什么的。从概念上讲,你想要做的事实际上并没有意义;它是处理程序的逻辑,而不是事件本身。

查看this帖子,了解模拟所需效果的一些方法。

答案 2 :(得分:0)

Microsoft Reactive ExtensionsRx框架提供了将事件转换为可观察对象的方法。事件不能作为参数传递,但是可观察事件可以。当订阅观察者时,他们为基础事件设置处理程序。

签名(其中一个重载)如下所示:

IObservable<EventPattern<TEventArgs>> FromEventPattern<TDelegate, TEventArgs>(
        Action<TDelegate> addHandler, Action<TDelegate> removeHandler
    ) where TEventArgs: EventArgs

例如,要从事件中定义MouseMove observable,可以使用此代码:

        IObservable<EventPattern<MouseEventArgs>> mouseMoves =
            Observable
                .FromEventPattern<MouseEventHandler, MouseEventArgs>(
                    h => richTextBox1.MouseMove += h,
                    h => richTextBox1.MouseMove -= h);

然后,您可以传递对IObservable<EventPattern<MouseEventArgs>> mouseMoves的引用并订阅它,如下所示:

        var subscription = 
            mouseMoves
                .Subscribe(ep =>
                {
                    var x = ep.EventArgs.X;
                    var y = ep.EventArgs.Y;
                    // etc
                });

从observable / event中分离就像调用它一样简单:

        subscription.Dispose();

你可以通过Nuget获得Rx。

答案 3 :(得分:0)

不幸的是,尽管.net中的事件和属性存在于类型系统中,虽然对于Microsoft来说它们既可以作为具体类型存在也是可行的(每个实例都包含一对委托,用于添加/ remove或for get / set),微软没有创建任何这样的具体类型,也没有看到这样做。因此,没有一种远程好看的方式将属性或事件传递给例程。相反,对于事件,要么必须传递一对委托 - 一个用于Add方法,一个用于Remove方法,或者可能传递一个包含两个委托的类或结构有问题,或者传递应该使用其事件的对象以及事件的名称,并让被调用的例程使用Reflection来找到与命名事件关联的添加/删除处理程序。