如何在 GUI 事件上调用回调函数?代表?

How to call a callback function on a GUI event? Delegates?

我是 C# 的新手,我想知道在这里使用委托是否正确:

我在 Visual Studio Windows Forms Designer 中创建了一个 UserControl。 在 TableLayoutPanel 中,我有 3 x 3 个这样的用户控件。他们每个人都通过构造函数获得一个行和列索引。

现在,在我包含 TableLayoutPanel 的表单中,我想在单击其中一个 UserControl 时调用一个函数,并在该函数调用中包含行和列索引。

我知道如何处理 UserControl 中的 Click 事件。但我不知道如何调用某种可以向 UserControl 注册的回调。 所以 UserControl 的 Click 事件处理程序会调用类似 Callback(Row, Col);

的东西

但我不知道如何将我的窗体的方法获取到用户控件中。在 C 中,我会使用函数指针。我这里需要代表吗?

所以在我的 UserControl 部分 class 我会有这样的东西:

public delegate void DoubleClickHandler(int row, int col);
public DoubleClickHandler Callback;

public void On_Click(object sender, EventArgs e)
{
    Callback(Row, Col);
}

创建表单时我会做类似的事情:

MyControl elem = new MyControl(1, 3);
elem.Callback = delegate (int row, int col) { Console.WriteLine("row {0}, col {1}", row, col); }

它有效,但我不知道这是否是正确的方法。

Winforms 可能会为此使用事件;相同的想法,不同的关键字例如

活动道具

//old
public DoubleClickHandler Callback;

//new
public event EventHandler<(int Row, int Col)> SomethingDoubleClicked;  //use a past tense name if you raise after, or a "SomethingDoubleClicking" if you raise before - probably hard to raise a click event before but..

OnClick 可能有这样的代码

var eh = SomethingDoubleClicked;
eh?.Invoke(this, (theRow, theCol));

订阅可能如下所示:

//"modern"
yourcontrol.SomethingDoubleClicked += (s, e) => Console.WriteLine("row {0}, col {1}", e.Row, e.Col);



//"classic"
yourcontrol.SomethingDoubleClicked += SomeControl_SomethingDoubleClicked;

void SomeControl_SomethingDoubleClicked(object sender, (int Row, int Col) e)
{
    Console.WriteLine("row {0}, col {1}", e.Row, e.Col);
}

注意 += 而不是 = - event 在概念上是一个方法列表,应该以未定义的顺序调用

随意将 EventHandler 中的元组更改为 class 或其他内容。也可以从 EventArgs 派生,但不是必须的。

如果您没有要报告的用户状态,您可以简化为使用:

public event EventHandler SomethingDoubleClicked; 

//onclick
var eh = SomethingDoubleClicked;
eh?.Invoke(this, EventArgs.Empty);

ourcontrol.SomethingDoubleClicked += (s, e) => ...;

但我可能会避免从 EventArgs 派生以提供自定义用户状态,然后使用上面的 EventHandler 表单 - 它会起作用,因为当你这样做时:

eh?.Invoke(this, new MyCustomEventArgs(...));

MyCustomEventArgs 派生自 EventArgs,因此您可以在父类型中传递子 class,但这意味着使用它的开发人员必须将其转换回去:

void SomeControl_SomethingDoubleClicked(object sender, EventArgs e)
{
    var mcea = e as MyCustomEventArgs;
}

而且有点恶心;最好使用 EventHandler<MyCustomEvenArgs> 使其成为 TAB TAB/no 转换事件