摘要:主要從面向對象的基本概念出發,分析了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#是純面向對象的語言,新建一個窗體就相當于定義了一個類,在實際使用時是必需要對窗體進行實例化的。
在新建一個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類的實例化并實現窗體的顯
示的。
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窗體。
}
}
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)
{
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先進行實例化。
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();
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 設置訪問權限的方式
對上面例子改進來說明其使用方式。在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)
{
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中的數據。
4.2 通過重載構造函數方式
用設置訪問權限的方式來傳遞窗體間的信息,與面向對象的封裝性不符。如果只是把主調用窗體的一些數據傳遞到被調窗體,比如:登錄窗體中用戶輸入用戶名和密碼并通過驗證后,在調出的窗體中顯示用戶名,那么采用重載窗體的構造函數的方式是比較適當的。如下面對Form2的構造函數重載后的代碼。
在Form1中調用Form2,在實例化時改為:Form2 frm2 = new Form2(\"張三\");
那么Form2中的就要增加一個重載的構造函數:
public partial class Form2 : Form
{
string uname1=1;
public Form2()
{
InitializeComponent();
}
public Form2(stringuname )
{
InitializeComponent();
uname1 = uname;
}
private void Form2_Load(object sender, EventArgs e)
{
this.Text = uname1 + \"welcome\";
}
}

細心的讀者已經發現,這種方法明顯存在一個主要缺點,就是主窗體向從窗體傳遞數據的數目是固定的而且中只能是實現主調窗體向被調窗體傳遞數據。
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
{
……
private void Form2_Load(object sender, EventArgs e)
{
label1.Text=this.Owner.Controls[0].Text;
}
}
運行結果如下圖所示:

5 結束語
以上所有的方法是本人在編程實踐中經過一段時間的研究與總結,C#窗體間的調用及數據傳遞方式不外乎就這幾種方式。無論是調用方法還是數據傳遞方式,使用時可以根據自身項目的需要靈活選擇。以上代碼已經過測試。在文章中為了方便,主調窗體的名稱Form1與被調用的窗體Form2名稱都沒有更改,希望讀者在實際項目的開發中養成及時把窗體名稱修改成有實際意義的名稱。
參考文獻:
[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