C#窗体间相互调用及数据传递方法
作者:方玉燕 楼 瑾
来源:《电脑知识与技术·学术交流》2008年第09期
摘要:主要从面向对象的基本概念出发,分析了C#中的Form类,重点介绍了在C#中如何实现窗体间的相互调用方法,以及窗体间数据传递方法与实现技术。 关键词:类;C#;窗体;数据传递
中图分类号:TP312文献标识码:A文章编号:1009-3044(2008)09-11645-05
The Methods of Calling form and Data Transmission with Visual C# FANG Yu-yan1, LOU Jin2
(1.Zhejiang University of Technology, Hangzhou 310014, China; 2.Hangzhou Dianzi University, Hangzhou 310014, China)
Abstract: Mainly based on the core concept of object-oriented, has analyzed the form class in visual C#, introduced with emphasis how to realize calling form mutually in Visual C#. Simultaneouslydiscussed between the different window forms data transmission methods. Key words: Class; Visual C#; Window form; Data transmission
初学C#时,有很多人对窗体间的相互调用方式总是不能很好的理解,在实现过程中总会遇到很多问题,把对窗体间互操作的一些实质进行了归纳总结,希望对初学者有所帮助。C#窗体间的互操作主要是指窗体间的相互调用和数据的传递。
1 Form类
在正式讲解窗体间的互相调用之前,先了解一下C#中窗体的实质。C#是纯面向对象的语言,新建一个窗体就相当于定义了一个类,在实际使用时是必需要对窗体进行实例化的。
龙源期刊网 http://www.qikan.com.cn
在新建一个Windows应用程序时,Visual Studio会自动生成一个Form1.cs和Program.cs二个文件。在2005以后的版本中,Form1.cs下还多了一个Form1.Designer.cs文件,用于存放窗体内生成控件的代码。
打开Form1.cs代码视图中可以看到代码如下,这是一个典型的类定义。 public partial class Form1: Form {
public Form1() //这是构造函数,调用Form1.Designer.cs中的控件初始化方法。 {
InitializeComponent(); }
private void button1_Click(object sender, EventArgs e) //事件方法 { } }
打开Program.cs代码可以看到程序代码如下: static void Main() { ……
Application.Run(new Form1()); //实例化Form1同时使Form1窗体可见。 }
Form1.cs和Form1.Designer.cs这二个文件结合起来就是对窗体Form1类的一个完整定义。学习过面向对象编程方式的人都知道,完成类定义并不能真正的使用,还要对类进行实例化。在程序运行时,是通过运行Program.cs文件的程序入口方法Main()中的Application.Run (new Form1())语句来实现窗体Form1类的实例化并实现窗体的显
龙源期刊网 http://www.qikan.com.cn
示的。
2 单窗体之间的相互调用
如果要在某个窗体中调用另外一个窗体,那么首先要对这个被调用的窗体进行实例化。下面用一个简单的实例来说明。
在Visual Studi 2005中新建一个项目,在项目中新建二个窗体Form1和Form2,也即新建了Form1和Form2二个类,窗体设计如下图1。要求能实现下列的操作,在Form1中单击“调用form2”按钮后,打开窗体Form2,单击Form2中的“关闭”按钮关闭Form2窗体。
在Form1窗体中双击“调用form2”按钮(或在事件窗口中查找click事件双击),生成按钮单击事件,在事件中写入代码,如下: public partial class Form1 : Form { ……
private void button1_Click(object sender, EventArgs e) {
Form2 frm2 = new Form2(); //要在Form1中调用Form2,要对Form2先进行实例化,实例化对象名为frm2。
frm2.Show();//显示Form2窗体。 } }
龙源期刊网 http://www.qikan.com.cn
Form2按钮的单击事件代码如下: public partial class Form2 : Form { ……
private void button1_Click(object sender, EventArgs e) {
this.Close();//也可以用this.Dispose()。单击相应按钮后关闭本窗体。 } }
窗体的显示与关闭是通过窗体的方法来实现的,不同的方法有不同功能,具体使用时可以根据要实现的目标选择合适的方法。下表列出了几个与窗体操作相关的几个方法,并作简要说明:
注意:被Dispose()或Close()的窗体不能再被Show()或ShowDialog(),要重新实例化后才能用打开。
当然如果要在Form2中调用Form1,那么只要修改Form2中的button1_Click事件代码,如下:
public partial class Form2 : Form { ……
private void button1_Click(object sender, EventArgs e)
龙源期刊网 http://www.qikan.com.cn
{
Form1 frm1 = new Form1 (); frm1.show()
this.Close(); //也可以用this.Dispose()。 } }
上例中虽然Form2是由Form1进行实例化并打开,但Form1在Form2中被重新实例化了,这样调用出来的与原来调用Form2的Form1不是同一个窗体。有时希望进行这样的操作,在Form1中打开Form2同时关闭Form1,在Form2中完成操作后回到原来的Form1中,并且访问原来Form1中的信息。下面的方法解决了这个问题。
3 指定所有者的窗体调用
3.1 采用模式窗体的打开与关闭
模式窗体的打开,一般通过Form.ShowDialog ()方法或它的一个重载方法
Form.ShowDialog (IWin32Window)来实现,其中后一个方法将窗体显示为具有指定所有者的模式对话框。
修改上例的代码如下: public partial class Form1 : Form { ……
private void button1_Click(object sender, EventArgs e) {
Form2 frm2 = new Form2(); //要在Form1中调用Form2,要对Form2先进行实例化。
龙源期刊网 http://www.qikan.com.cn
this.Hide();//隐藏Form1窗体。
frm2.ShowDialog(this); // 对于指定所有者方式打开的模式窗体,这样可以在模式窗体内部获取主窗体的引用。 } }
public partial class Form2 : Form { ……
private void button1_Click(object sender, EventArgs e) {
this.Owner.Show();//显示所有者窗体,也即Form1。 this.Close();//关闭本窗体 } }
3.2 指定回调对象的方法
也可以采用指定回调对象的方法来实现回调窗体的方式来完成,那么就要修改代码,如下:
Form1中“调用form2”按钮的单击事件代码: private void button1_Click(object sender, EventArgs e) {
Form2 frm2 = new Form2();
frm2.frm1 = this; //要在Form2中调用Form1,这个语句非常关键,是把Form2中的frm1这个字段指回本窗体。 frm2.Show();
龙源期刊网 http://www.qikan.com.cn
this.Hide(); //在这里不能用Close的方法,否则全部都关闭了。 }
Form2中的“关闭”按钮单击事件代码: public partial class Form2 : Form {
public Form1 frm1 = new Form1(); //在Form2中实例化Form1为frm1,此时frm1是作为Form2这个类的一个字段,类型为public。//
private void button1_Click(object sender, EventArgs e) {
frm1.Show(); this.Close(); } }
当然用这种方法实现互调也存在一个问题,由于在Form2中添加了public Form1 frm1,造成了Form2与Form1耦合度的增加,如果不用实现Form2向Form1回调数据,尽量不要使用定义public类型的数据来实现。
4 窗体间的数据传递
窗体间的调用,关键还是相互访问窗体的信息。窗体间的数据传递总体上可以分为二大类,一种是主调窗体访问被调窗体的数据,另外一种是被调窗体获取主调窗体的数据。前者可以采用设置访问权限为“public”的方式,这种方式增加了窗体间的耦合度,但简单方便;另外一种方法是给相关的窗体类编写重载构造函数或采用所有者的模式调用窗体。 4.1 设置访问权限的方式
龙源期刊网 http://www.qikan.com.cn
对上面例子改进来说明其使用方式。在Form1中要访问的Form2的textBox1控件,只要把Form2的textBox1控件Modifiers属性设置为public。相应的,在form2中要对Form1中的字段变量a进行访问,也要把字段变量a的访问权限设置为public,当然也可以把a写成属性。
下面代码实现的功能用三个图的表示:
Form1的相关代码:
public partial class Form1 : Form {
public int a = 1000; ……
private void button1_Click(object sender, EventArgs e)
龙源期刊网 http://www.qikan.com.cn
{
Form2 frm2 = new Form2(); frm2.frm1 = this; this.Hide();
frm2.ShowDialog(); //注意在这里不能用show方法,否则得不到预期的结果。 label1.Text = a.ToString(); label2.Text = frm2.textBox1.Text; } }
Form2的相关代码
public partial class Form2 : Form {
public Form1 frm1 = new Form1(); ……
private void button1_Click(object sender, EventArgs e) {
frm1.a = 20000; frm1.Show();
this.Hide(); //如果这里采用Close方法,在Form1中就访问不到Form2的TextBox1控件 } }
上述的方法实现了在Form1中访问Form2的数据,同时也能在Form2中访问Form1中的数据。
龙源期刊网 http://www.qikan.com.cn
4.2 通过重载构造函数方式
用设置访问权限的方式来传递窗体间的信息,与面向对象的封装性不符。如果只是把主调用窗体的一些数据传递到被调窗体,比如:登录窗体中用户输入用户名和密码并通过验证后,在调出的窗体中显示用户名,那么采用重载窗体的构造函数的方式是比较适当的。如下面对Form2的构造函数重载后的代码。
在Form1中调用Form2,在实例化时改为:Form2 frm2 = new Form2(\"张三\"); 那么Form2中的就要增加一个重载的构造函数: public partial class Form2 : Form {
string uname1=null; public Form2() {
InitializeComponent(); }
public Form2(stringuname ) {
InitializeComponent(); uname1 = uname; }
private void Form2_Load(object sender, EventArgs e) {
this.Text = uname1 + \"welcome\"; } }
龙源期刊网 http://www.qikan.com.cn
细心的读者已经发现,这种方法明显存在一个主要缺点,就是主窗体向从窗体传递数据的数目是固定的而且中只能是实现主调窗体向被调窗体传递数据。 4.3 指定窗体的所有者访问方式的数据传递
如果只是为在被调窗体中访问主调窗体的数据,采用重载构造函数方式不仅比较麻烦要写重载的构造函数,而且传递数据的数目是固定,采用所有者模式进行访问的数据可以避免这个弊端,。
因为采用所有者进行访问的窗体属于被调用的窗体,因此可以访问窗体的Owner属性,如果以Form.ShowDialog ()/Form.Show()方式打开,Form.Owner属性会是空引用。 public partial class Form1 : Form { ……
private void button1_Click(object sender, EventArgs e) {
Form2 frm2 = new Form2();//要在Form1中调用Form2,要对Form2先进行实例化。 frm2.ShowDialog(this);// 对于指定所有者方式打开的模式窗体,这样可以在模式窗体内部获取主窗体的引用。 } }
public partial class Form2 : Form {
龙源期刊网 http://www.qikan.com.cn
……
private void Form2_Load(object sender, EventArgs e) {
label1.Text=this.Owner.Controls[0].Text; } }
运行结果如下图所示:
5 结束语
以上所有的方法是本人在编程实践中经过一段时间的研究与总结,C#窗体间的调用及数据传递方式不外乎就这几种方式。无论是调用方法还是数据传递方式,使用时可以根据自身项目的需要灵活选择。以上代码已经过测试。在文章中为了方便,主调窗体的名称Form1与被调用的窗体Form2名称都没有更改,希望读者在实际项目的开发中养成及时把窗体名称修改成有实际意义的名称。
参考文献:
龙源期刊网 http://www.qikan.com.cn
[1] (美)Christian Nagel. (译者)李敏波 C#高级编程[M] 第四版.中国:清华大学出版社,出版年.2006-10.1-1191.
[2] 祝宇. Windows窗体间的消息传递[J].电脑编程技巧与维护.2007.7:57-59. [3] Microsoft Corporatin《MSDN Library For Visual Studio 2005》the United States of America 8.0.5.727.42 RTM
[4] C#不同窗体间通信,数据传递
[EB/OL]http://tb.blog.csdn.net/TrackBack.aspx?PostId=16947542007-7 [5] .net平台开发中的模式窗体[EB/OL]
http://zxbc.cn/html/netfra/200704182214232098.htm2007-4
因篇幅问题不能全部显示,请点此查看更多更全内容