19

是否有可能在任何情况下都能够做到这一点?

我现在的情况是这样的:

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.
    }
}

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

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

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

4

4 回答 4

31

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

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

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

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

public void CustomForm_Click(object sender, MouseEventArgs e)        
{
    _elements[0].PerformClick();
}
于 2008-09-20T11:52:34.383 回答
10

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

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

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

然后你可以像这样从类外部调用事件。

myCustomGUIElement.Click(sender,args);

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

myCustomGUIElement.Click = null;

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

于 2008-09-21T20:56:26.657 回答
3

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

public event Action<int> RecipeSelected;
public void RaiseRecpeSelected(int recipe) => RecipeSelected?.Invoke(recipe);
于 2019-07-12T12:33:56.763 回答
1

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

于 2008-09-20T11:52:23.963 回答