从所属类外部调用 C# 事件?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/107972/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-03 14:15:29  来源:igfitidea点击:

Calling C# events from outside the owning class?

提问by Matthew Scharley

Is it possible under any set of circumstances to be able to accomplish this?

在任何情况下都可以做到这一点吗?

My current circumstances are this:

我现在的情况是这样的:

public class CustomForm : Form
{
    public class CustomGUIElement
    {
    ...
        public event MouseEventHandler Click;
        // etc, and so forth.
    ...
    }

    private List<CustomGUIElement> _elements;

    ...

    public void CustomForm_Click(object sender, MouseEventArgs e)
    {
        // we might want to call one of the _elements[n].Click in here
        // but we can't because we aren't in the same class.
    }
}

My first thought was to have a function similar to:

我的第一个想法是有一个类似于:

internal enum GUIElementHandlers { Click, ... }
internal void CustomGUIElement::CallHandler(GUIElementHandler h, object[] args) {
    switch (h) {
        case Click:
            this.Click(this, (EventArgs)args[0]);
            break;
        ... // etc and so forth
    }
}

It's a horribly ugly kludge, but it should work... There must be a more elegant solution though? The .NET library does this all the time with message handlers and calling events in Control's. Does anyone else have any other/better ideas?

这是一个非常丑陋的kludge,但它应该可以工作......但是必须有一个更优雅的解决方案吗?.NET 库始终使用消息处理程序和 Control 中的调用事件来执行此操作。有没有其他人有任何其他/更好的想法?

采纳答案by Phil Wright

You just need to add a public method for invoking the event. Microsoft already does this for some events such as PerformClickfor controls that expose a Clickevent.

您只需要添加一个公共方法来调用事件。Microsoft 已经为某些事件执行了此操作,例如用于公开Click事件的控件的PerformClick

public class CustomGUIElement    
{
    public void PerformClick()
    {
        OnClick(EventArgs.Empty);
    }

    protected virtual void OnClick(EventArgs e)
    {
        if (Click != null)
            Click(this, e);
    }
}

You would then do the following inside your example event handler...

然后,您将在示例事件处理程序中执行以下操作...

public void CustomForm_Click(object sender, MouseEventArgs e)        
{
    _elements[0].PerformClick();
}

回答by Per Hornsh?j-Schierbeck

You really should wrap the code you want to be able to execute from the outside in a method. That method can then do whatever your event would do - and that event would also instead call that method.

您确实应该将希望能够从外部执行的代码包装在一个方法中。然后该方法可以执行您的事件将执行的任何操作 - 该事件也将调用该方法。

回答by Lee

The event keyword in c# modifies the declaration of the delegate. It prevents direct assignment to the delegate (you can only use += and -= on an event), and it prevents invocation of the delegate from outside the class.

c# 中的 event 关键字修改了委托的声明。它防止直接分配给委托(您只能在事件上使用 += 和 -=),并防止从类外部调用委托。

So you could alter your code to look like this:

因此,您可以将代码更改为如下所示:

public class CustomGUIElement
{
...
    public MouseEventHandler Click;
    // etc, and so forth.
...
}

Then you can invoke the event from outside the class like this.

然后,您可以像这样从班级外部调用该事件。

myCustomGUIElement.Click(sender,args);

The drawback is that code using the class can overwrite any registered handlers very easily with code like this:

缺点是使用该类的代码可以很容易地用这样的代码覆盖任何注册的处理程序:

myCustomGUIElement.Click = null;

which is not allowed if the Click delegate is declared as an event.

如果将 Click 委托声明为事件,则不允许这样做。

回答by Larry

You can shorten the code suggested in the accepted answer a lot using the modern syntax feature of the .NET framework:

您可以使用 .NET 框架的现代语法功能大量缩短已接受答案中建议的代码:

public event Action<int> RecipeSelected;
public void RaiseRecpeSelected(int recipe) => RecipeSelected?.Invoke(recipe);