如何将事件传递给一个方法?

28
我希望创建一个方法,它以事件作为参数,并将eventHandler添加到事件中以正确处理它。就像这样:

我有两个事件:

public event EventHandler Click;
public event EventHandler Click2;

现在我想像这样将特定事件传递给我的方法(伪代码):

public AttachToHandleEvent(EventHandler MyEvent)
{
    MyEvent += Item_Click;
}

private void Item_Click(object sender, EventArgs e)
{
    MessageBox.Show("lalala");
}

ToolStripMenuItem tool = new ToolStripMenuItem();
AttachToHandleEvent(tool.Click);

这可行吗?

我注意到这段代码运行良好,然后回到我的项目发现,当我传递在我的类中声明的事件时,它能正常工作,但是当我传递来自其他类的事件时,它仍然无法工作。

我收到的错误消息如下:

事件'System.Windows.Forms.ToolStripItem.Click'只能出现在+=或-=的左侧。


@Petar Minchev 我不知道为什么... 你第一个帮助了我。谢谢。 - Tom Smykowski
我已经更新了问题以反映我仍在处理的问题。 - Tom Smykowski
@tomaszs 看看我的修改。这是因为之前事件是在调用它的同一个类中声明的。 - Petar Minchev
9个回答

29

我的原始答案适用于定义事件的类内部,但是您后来更新了问题,表示希望从定义类外部完成此操作,因此我将其删除。

只有定义事件的类可以引用事件使用的隐式委托变量。从该类外部,您只能通过+=-=访问addremove方法。这意味着您无法直接实现您所要求的内容。但是,您可以使用函数式方法。

class A{
    public event EventHandler Event1;

    public void TriggerEvent1(){
        if(Event1 != null)
            Event1(this, EventArgs.Empty);
    }
}

class B{
    static void HandleEvent(object o, EventArgs e){
        Console.WriteLine("Woo-hoo!");
    }

    static void AttachToEvent(Action<EventHandler> attach){
        attach(HandleEvent);
    }

    static void Main(){
        A a = new A();
        AttachToEvent(handler=>a.Event1 += handler);
        a.TriggerEvent1();
    }
}

我已经检查了我的问题的更新版本,不幸的是它仍然无法工作,你能帮我吗? - Tom Smykowski

6
我是这样做的:
public AttachToHandleEvent(Object obj, string EventName)
{
    EventInfo mfi = obj.GetType().GetEvent(EventName);
    MethodInfo mobj = mfi.GetAddMethod();
    mobj.Invoke(obj, new object[] { Item_Click});
}

private void Item_Click(object sender, EventArgs e)
{
    MessageBox.Show("lalala");
}

ToolStripMenuItem tool = new ToolStripMenuItem();
AttachToHandleEvent(tool "Click");

感谢您们的建议。没有您们的帮助,这个解决方案就无法完成。

这段代码有一些问题。解决方案在这里:http://msdn.microsoft.com/en-us/library/ms228976%28v=vs.95%29.aspx#Y899 - cbp

2

只需编写 tool.Click += Item_Click;

编辑:根据MSDN的说法,“事件只能从声明它们的类或结构中调用”。因此,您正在尝试的操作是不可能的。您能否更详细地阐述您的需求?为什么要将事件作为参数传递?


1
不是我的问题。你的答案是第一个并且正确的。我尝试了这段代码的较长版本但它无法工作。我在这里发布了这个问题来寻求帮助,但当你回答后,我重新检查了这个简单的例子,发现它和你写的一样是正确的。谢谢。 - Tom Smykowski
1
仍然有问题。抱歉之前提问不够准确,现在更加明确地描述问题,重点是当我遇到错误时的情况。 - Tom Smykowski
我无法这样做,因为我想要将附加到 Click 事件的操作放在 AttachToHandleEvent 中。 - Tom Smykowski
这是针对你原始回答的回应:“我没有看到问题,代码在语义上是正确的。编辑:你问是否可能,那就试试吧: )。尝试一下所需的时间比在这里提问少。” - Jamie Ide
1
我不会因为一个看起来像傻瓜粉色独角兽的人而感到冒犯。 - Jamie Ide
显示剩余8条评论

2

这是不可能的。如果符合您的需求,您可以使用委托代替事件。


1
    delegate void doIt(object sender, object data);
    event doIt OnDoIt;

    void add(doIt theDel)
    {
        OnDoIt += theDel;
    }

    void doIt1(object a, object b)
    {
    }

    void doIt2(object a, object b)
    {
    }

    void add()
    {
        add(doIt1);
        add(doIt2);
    }

0

你的问题表明你对一些机制存在误解:你不能传递事件!

你很可能想要将一个函数作为参数传递,这样调用方法就会在某个时刻调用另一个方法。从技术上讲,这就是委托。我建议使用已经定义好的Action类。下面是一个示例片段:

void MyFunction (string otherArguments, Action onFinished){
    ...
    if (onFinished != null)
        onFinished.Invoke();
}

这个好处在于调用 MyFunction 时,你可以使用内联语法声明 Action:

MyFunction("my other argument", ()=>{
    ///do stuff here, which will be execuded when the action is invoked
});

0
用对象导向的解决方案更新此问题。
不必使用注册事件的 Action<EventHandler>,您可以创建一个对象来处理它。
    public class AEvent
    {
        private readonly A aInstance;
        private AEvent(A instance) {
            aInstance = instance;
        }        

        public void Add(EventHandler eventHandler)
            => a.Event1 += eventHandler;

        public void Remove(EventHandler eventHandler)
            => a.Event1 -= eventHandler;

        public EventHandler Invoke => aInstance.Event1;
    }

然后稍后像这样使用该对象:
    static void Main(){
        A a = new A();
        AEvent aEvent = new AEvent(A)
        aEvent.Add(handler);
        a.Invoke();
    }

0

我在这里没有看到的一种方法是创建一个对象,该对象具有订阅和取消订阅的委托。以下是完整的示例程序。

class Program
{
    private event EventHandler<EventArgs> eventHandler;

    public static void Main(string[] args)
    {
        Program program = new Program();
        Thing thing = new Thing(new EventWrapper<EventArgs>(
            delegate(EventHandler<EventArgs> handler) { program.eventHandler += handler; },
            delegate(EventHandler<EventArgs> handler) { program.eventHandler -= handler; }
        ));

        // events are fired
        program.eventHandler?.Invoke(program, EventArgs.Empty);

        thing.Unsubscribe();
    }
}

class Thing
{
    private readonly Action<EventHandler<EventArgs>> _unsubscribeEventHandler;

    public Thing(EventWrapper<EventArgs> eventHandler)
    {
        this._unsubscribeEventHandler = eventHandler.Unsubscribe;
        eventHandler.Subscribe?.Invoke(OnEvent);
        Console.WriteLine("subscribed");
    }

    private void OnEvent(object? sender, EventArgs e)
    {
        Console.WriteLine("event fired");
    }

    public void Unsubscribe()
    {
        _unsubscribeEventHandler?.Invoke(OnEvent);
        Console.WriteLine("unsubscribed");
    }
}

class EventWrapper<T> where T : EventArgs
{
    public Action<EventHandler<T>> Subscribe { get; private set; }
    public Action<EventHandler<T>> Unsubscribe { get; private set; }

    public EventWrapper(Action<EventHandler<T>> subscribe, Action<EventHandler<T>> unsubscribe)
    {
        Subscribe = subscribe;
        Unsubscribe = unsubscribe;
    }
}

在这个例子中,我们创建了一个名为 EventWrapper<T> 的新类,它包装了 +=-= 的委托,并使用 SubscribeUnsubscribe 方法公开它们。这些委托将需要由创建事件的类创建。

请给我关于这个答案的反馈。我还在学习 .net,如果这是一种反模式或会引起问题,我想知道。谢谢。 - Kyle Shrader

0

我像这样传递函数/方法(而不是事件):

class A
{
    public void something()
    {
        var myAction = 
            new Action<object, object>((sender, evArgs) => {
                MessageBox.Show("hiii, event happens " + (evArgs as  as System.Timers.ElapsedEventArgs).SignalTime); 
            });
        B.timer(myAction);
    }
}

class B
{
    public static void timer( Action<object, System.Timers.ElapsedEventArgs> anyMethod)
    {
        System.Timers.Timer myTimer = new System.Timers.Timer();
        myTimer.Elapsed += new System.Timers.ElapsedEventHandler(anyMethod);
        myTimer.Interval = 2000;
        myTimer.Start();
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接