Bob*_*lan 38 c# properties winforms
我有两种形式,一种是主要形式,另一种是选项形式.例如,假设用户点击主窗体上的菜单:Tools -> Options
这将导致我的选项表单显示.
我的问题是如何将我的选项表单中的数据发送回我的主表单?我知道我可以使用属性,但我有很多选择,这似乎是一件单调乏味的事情.
那么最好的方法是什么?
thi*_*eek 57
Form1触发Form2打开.Form2重载了构造函数,它将调用form作为参数,并提供对Form2成员的引用.这解决了通信问题.例如,我在Form1中将Label Property公开为public,并在Form2中进行了修改.
通过这种方法,您可以以不同的方式进行通信.
// 你的Form1
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
Form2 frm = new Form2(this);
frm.Show();
}
public string LabelText
{
get { return Lbl.Text; }
set { Lbl.Text = value; }
}
}
Run Code Online (Sandbox Code Playgroud)
// 你的Form2
public partial class Form2 : Form
{
public Form2()
{
InitializeComponent();
}
private Form1 mainForm = null;
public Form2(Form callingForm)
{
mainForm = callingForm as Form1;
InitializeComponent();
}
private void Form2_Load(object sender, EventArgs e)
{
}
private void button1_Click(object sender, EventArgs e)
{
this.mainForm.LabelText = txtMessage.Text;
}
}
Run Code Online (Sandbox Code Playgroud)
替代文字http://demo.ruchitsurati.net/files/frm1.png
alt text http://demo.ruchitsurati.net/files/frm2.png
Pet*_*iho 15
在接受回答的评论中,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 += (sender, e) => Lbl.Text = ((Form2)sender).Message;
frm.Show();
}
}
Run Code Online (Sandbox Code Playgroud)
上面的代码创建了一个新实例Form2
,然后在显示它之前,为该表单的Button1Click
事件添加了一个事件处理程序.
请注意,(sender, e) => Lbl.Text = ((Form2)sender).Message
编译器会自动将表达式转换为类似于(但绝对不完全相同)的方法:
private void frm_Message(object sender, EventArgs e)
{
Lbl.Text = ((Form2)sender).Message;
}
Run Code Online (Sandbox Code Playgroud)
实际上有很多方法/语法可以实现和订阅事件处理程序.例如,使用如上所述的匿名方法,您实际上不需要转换sender
参数; 相反,你可以直接使用frm
局部变量:(sender, e) => 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);
}
}
}
Run Code Online (Sandbox Code Playgroud)
除了事件之外,我还声明了一个属性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));
}
}
}
Run Code Online (Sandbox Code Playgroud)
然后订阅者可以直接从事件对象中检索消息值:
frm.Button1Click += (sender, e) => Lbl.Text = e.Message;
Run Code Online (Sandbox Code Playgroud)
所有上述变化中重要的一点是,课程在任何时候都不Form2
需要知道任何事情Form1
.有Form1
知道Form2
是不可避免的; 毕竟,这是将创建一个新Form2
实例并使用它的对象.但是这种关系可以是不对称的,任何需要它提供的功能的对象Form2
都可以使用它.通过将功能公开为事件(并且可选地具有属性),它使其自身有用而不仅限于其对类的有用性.Form1