2

事件处理程序

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

4 回答 4

1

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

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

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

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

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

于 2012-11-18T22:44:09.603 回答
1

您正在与代表混合事件。您可能应该阅读Jon Skeet 的这篇文章,它将解释两者之间的差异。

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

我不确定你正在尝试什么可以完成。从概念上讲,您想做的事情实际上没有意义;这是您要传递的处理程序的逻辑,而不是事件本身。

看看这篇文章,它着眼于一些模拟你想要的效果的方法。

于 2012-11-18T22:47:19.820 回答
0

Microsoft Reactive ExtensionsRx框架提供了一种将事件转换为可观察对象的方法。事件不能作为参数传递,但 observables 可以。当订阅 observables 时,它们会为底层事件设置处理程序。

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

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

例如,MouseMove要从事件定义可观察对象,可以使用以下代码:

        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
                });

从可观察/事件中分离变得像这样简单:

        subscription.Dispose();

您可以通过 Nuget 获得 Rx。

于 2012-11-18T23:03:21.477 回答
0

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

于 2012-11-19T22:49:43.623 回答