在接受答案的 cmets 中,Neeraj Gulia 写道:
这导致表单 Form1 和 Form2 紧密耦合,我想应该在这种情况下使用自定义事件。
评论完全正确。接受的答案还不错;对于简单的程序,尤其是对于那些刚刚学习编程并试图让基本场景发挥作用的人来说,这是一个非常有用的示例,可以说明一对表单如何交互。
但是,确实可以并且应该避免示例引起的耦合,并且在特定示例中,事件将以通用、解耦的方式完成相同的事情。
这是一个示例,使用接受的答案的代码作为基线:
Form1.cs:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
Form2 frm = new Form2();
frm.Button1Click += (s1, e1) => Lbl.Text = ((Form2)s1).Message;
frm.Show();
}
}
上面的代码创建了一个Form2 的新实例,然后在显示它之前,为该表单的Button1Click 事件添加了一个事件处理程序。
请注意,表达式(s1, e1) => Lbl.Text = ((Form2)s1).Message 会被编译器自动转换为看起来类似于(但绝对不完全相同)的方法:
private void frm_Message(object s1, EventArgs e1)
{
Lbl.Text = ((Form2)s1).Message;
}
实际上有很多方法/语法来实现和订阅事件处理程序。例如,使用上述匿名方法,您实际上不需要强制转换sender 参数;相反,您可以直接使用frm 局部变量:(s1, e1) => Lbl.Text = frm.Message。
反之,您不需要使用匿名方法。实际上,您可以像上面显示的编译器生成的那样声明一个常规方法,然后将该方法订阅到事件:frm.Button1Click += frm_Message;(您当然使用名称frm_Message 作为该方法,就像在我上面的例子中)。
不管你如何做,当然你需要Form2 来实际实现Button1Click 事件。这很简单……
Form2.cs:
public partial class Form2 : Form
{
public event EventHandler Button1Click;
public string Message { get { return txtMessage.Text; } }
public Form2()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
EventHandler handler = Button1Click;
if (handler != null)
{
handler(this, EventArgs.Empty);
}
}
}
除了事件之外,我还声明了一个属性 Message,它公开了 Text 属性(并且仅 Text 属性,实际上只是只读的) 的txtMessage 控件。这允许事件的订阅者获取该值并对其进行任何需要的操作。
请注意,该事件所做的只是提醒订阅者该按钮实际上已被点击。由订阅者决定如何解释或响应该事件(例如,通过检索 Message 属性的值并将其分配给某物)。
或者,您实际上可以通过声明一个新的 EventArgs 子类并将其用于事件来代替事件本身来传递文本:
public class MessageEventArgs : EventArgs
{
public string Message { get; private set; }
public MessageEventArgs(string message)
{
Message = message;
}
}
public partial class Form2 : Form
{
public event EventHandler<MessageEventArgs> Button1Click;
public Form2()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
EventHandler handler = Button1Click;
if (handler != null)
{
handler(this, new MessageEventArgs(txtMessage.Text));
}
}
}
然后订阅者可以直接从事件对象中检索消息值:
frm.Button1Click += (sender, e) => Lbl.Text = e.Message;
上述所有变体中的重要一点是,Form2 类在任何时候都不需要知道有关 Form1 的任何信息。让Form1 了解Form2 是不可避免的;毕竟,该对象将创建一个新的Form2 实例并使用它。但这种关系可能是不对称的,Form2 可供 任何 需要它提供的功能的对象使用。通过将功能公开为事件(并且可以选择使用属性),它使自己变得有用,而不会将其用处仅限于 Form1 类。