Windows
窗體是用于
Microsoft Windows
應用程序開發的、基于
.NET Framework
的新平臺。此框架提供一個有條理的、面向對象的、可擴展的類集,它使您得以開發豐富的
Windows
應用程序。一個
Windows
窗體就代表了
.NET
架構里的
System.Windows.Forms.Form
類的一個實例。
首先還是使用第一篇文章中的第二個例子,窗體如下:
作者在
CSDN
技術論壇
.NET
板塊下的
C#
分類經??吹接腥藛柶鹑绾卧趦蓚€
Form
間傳遞數據,訪問修改對方窗體里面的值。對于有經驗的程序員來說不是什么高深的東西,而對于初學者來說這些基礎的東西往往是一個問題,并且存在這種現象,往往比較復雜的東西他們會,要用什么了就去學什么,實際上并沒有真正的去理解掌握它,基礎不扎實,所以就有了想通過自己對窗體編程積累的經驗來寫一些這方面的文章,以供學
.NET
的朋友參考,也借此機會同各位朋友進行交流,寫得不合理的地方請各位朋友提寶貴意見,下面我分了三個部分來講。
<
第一個例子
>
說明:
Form1
為主窗體,包含控件:文本框
textBoxFrm1
,多選框checkBoxFrm1和按鈕buttonEdit;
Form2
為子窗體,包含控件:
文本框
textBoxFrm2
,多選框checkBoxFrm2和按鈕buttonOK,buttonCancel。
當我們新建一個窗體的時候,設計器會生成默認的構造函數:
public Form2()
{
InitializeComponent();
}
它不帶參數,既然我們要把Form1中的一些數據傳到Form2中去,為什么不在Form2的構造函數里做文章呢?
假設我們要實現使Form2中的文本框顯示Form1里textBoxFrm1的值,修改子窗體的構造函數:
public Form2(string text)
{
InitializeComponent();
this.textBoxFrm2.Text = text;
}
增加Form1中的修改按鈕點擊事件,處理函數如下:
private void buttonEdit_Click(object sender, System.EventArgs e)
{
Form2 formChild = new Form2(this.textBoxFrm1.Text);
formChild.Show();
}
我們把this.textBoxFrm1.Text作為參數傳到子窗體構造函數,以非模式方式打開,這樣打開的formChild的文本框就顯示了
”
主窗體
”
文本,是不是很簡單,接下來我們傳一個boolean數據給子窗體。
Public Form2(string text,bool checkedValue)
{
InitializeComponent();
this.textBoxFrm2.Text = text;
this.checkBoxFrm2.Checked = checkedValue;
}
在主窗體中的修改按鈕點擊處理,我采用了打開模式窗口的方式,其實在這個例子中看不出有什么分別,
private void buttonEdit_Click(object sender, System.EventArgs e)
{
Form2 formChild = new Form2(this.textBoxFrm1.Text,this.checkBoxFrm1.Checked);
formChild.ShowDialog();
}
結果在預料之中,但是這里明顯存在不足,在子窗體里的數據修改后不能傳給主窗體,也就是說主窗體不受子窗體的影響。而在實際的開發過程中我們經常使用子窗體來修改主窗體里面的數據,那怎么解決呢?
在.NET中有兩種類型,值類型和引用類型。值類型是從ValueType繼承而來,而ValueType又是從Object繼承;對于引用類型它直接繼承Object類型。這下讓我們看看怎樣通過Form2來修改Form1里的數據。
還是讓我們來修改Form2的代碼。
Private TextBox textBoxFrm12;
private CheckBox checkBoxFrm12;
public Form2(TextBox heckbo,CheckBox heckbox)
{
InitializeComponent();
this.textBoxFrm2.Text = heckbo.Text;
this.checkBoxFrm2.Checked = heckbox.Checked;
this.textBoxFrm12 = heckbo;
this.checkBoxFrm12 = heckbox;
}
現在我們傳了兩個引用類型的數據:TextBox類型,和CheckBox;另外在Form2中增加了兩個類數據成員textBoxFrm12、checkBoxFrm12用來分別保存構造函數傳來的變量,不過他們并不屬于Form2的Controls容器。修改Form2的確定按鈕點擊事件函數:
private void buttonOK_Click(object sender, System.EventArgs e)
{
this.textBoxFrm12.Text = this.textBoxFrm2.Text;
this.checkBoxFrm12.Checked = this.checkBoxFrm2.Checked;
this.Close();
}
上面的代碼我們通過把textBoxFrm2的Text和checkBoxFrm2.Checked賦給textBoxFrm12和checkBoxFrm12完成了對主窗體中的textBoxFrm1和checkBoxFrm2的修改,因為textBoxFrm1和textBoxFrm12是同一個引用,而checkBoxFrm2和checkBoxFrm12也是。
到這里為止功能是實現了,但是總覺得不是很合理,讓兩個窗體控件傳來傳去,現在我舉一個恰當一點的例子。
<
第二個例子>
說明:在這個例子中我們的兩個窗體都加了一個ListBox用來顯示ArrayList中的內容。
主窗體中控件:listBoxFrm1,buttonEdit;
子窗體中控件:listBoxFrm2,textBoxAdd,buttonAdd,buttonEdit,buttonOK。
這次我們用ArrayList來作為傳遞數據,在Form1中定義類數據成員:
private ArrayList listData1;
在構造函數中增加了對listData1進行內存分配,并生成數據最終綁定到listBoxFrm1,
public Form1()
{
InitializeComponent();
this.listData1 = new ArrayList();
this.listData1.Add("DotNet");
this.listData1.Add("C#");
this.listData1.Add("Asp.net");
this.listData1.Add("WebService");
this.listData1.Add("XML");
this.listBoxFrm1.DataSource = this.listData1;
}
另外,對修改按鈕點擊事件處理函數的修改如下:
private void buttonEdit_Click(object sender, System.EventArgs e)
{
Form2 formChild = new Form2(this.listData1);
formChild.ShowDialog();
this.listBoxFrm1.DataSource = null;
this.listBoxFrm1.DataSource = this.listData1;
}
相對與主窗體,對子窗體作相應修改,也在Form2中增加了類數據成員:
private ArrayList listData2;
用來保存對主窗體中listData1的引用。
修改構造函數:
public Form2(ArrayList listData)
{
InitializeComponent();
this.listData2 = listData;
foreach(object o in this.listData2)
{
this.listBoxFrm2.Items.Add(o);
}
}
這里讓listData2同listData1指向同一個引用;另外沒有對listBoxFrm進行綁定,采用了填充。
好了,下面是對數據操作的時候了。
添加處理函數代碼如下:
private void buttonAdd_Click(object sender, System.EventArgs e)
{
if(this.textBoxAdd.Text.Trim().Length>0)
{
this.listData2.Add(this.textBoxAdd.Text.Trim());
this.listBoxFrm2.Items.Add(this.textBoxAdd.Text.Trim());
}
else
MessageBox.Show("
請輸入添加的內容!");
}
刪除處理代碼如下:
private void buttonDel_Click(object sender, System.EventArgs e)
{
int index = this.listBoxFrm2.SelectedIndex;
if(index!=-1)
{
this.listData2.RemoveAt(index);
this.listBoxFrm2.Items.RemoveAt(index);
}
else
MessageBox.Show("
請選擇刪除項或者沒有可刪除的項!");
}
退出Form2子窗體:
private void buttonOK_Click(object sender, System.EventArgs e)
{
this.Close();
}
編譯運行程序,在子窗體中對數據進行修改,關閉后,主窗體就會顯示更新后的數據。
這里有一點要提醒一下,比較兩個例子,我們都傳的是引用類型,一個是String,另一個是ArrayList,為什么string類型不能修改主窗體的數據呢?其實在.Net中對string類型的修改并不是修改原來的值,原來的值沒有變化,而是重新生成一個新的字符串,下面是一個很好的說明。
public class ZZConsole
{
[STAThread]
static void Main(string[] args)
{
string str1 = "abc";
string str2 = str1;
str1 = "123";
Console.WriteLine(str1);
Console.WriteLine("--------------");
Console.WriteLine(str2);
Console.WriteLine("--------------");
ArrayList al1 = new ArrayList();
al1.Add("abc");
ArrayList al2 = al1;
al2.Add("123");
foreach(object o in al1)
Console.WriteLine((string)o);
Console.WriteLine("--------------");
foreach(object o in al2)
Console.WriteLine((string)o);
Console.ReadLine();
}
}
運行一下看看輸出結果就明白了,另外對值類型的數據操作要使用ref關鍵字。
總結,我們通過帶參數的構造函數實現了窗體間的數據交互,代碼看上去也比較清楚,在實際開發過程中,可以把DataSet,DataTable,或者是DataView當作參數,當然如果只是想修改一行,可以傳個DataRow或者DataRowView。
二.給窗體添加屬性或方法
1
.使用
Form
類的
Owner
屬性
獲取或設置擁有此窗體的窗體。若要使某窗體歸另一個窗體所有,請為其
Owner
屬性分配一個對將成為所有者的窗體的引用。當一個窗體歸另一窗體所有時,它便隨著所有者窗體最小化和關閉。例如,如果
Form2
歸窗體
Form1
所有,則關閉或最小化
Form1
時,也會關閉或最小化
Form2
。并且附屬窗體從不顯示在其所有者窗體后面??梢詫⒏綄俅绑w用于查找和替換窗口之類的窗口,當選定所有者窗體時,這些窗口不應消失。若要確定某父窗體擁有的窗體,請使用
OwnedForms
屬性。
上面是
SDK
幫助文檔上講的,下面我們就來使用它。


說明:在這個例子中我們的兩個窗體都加了一個ListBox用來顯示ArrayList中的內容。
主窗體中控件:listBoxFrm1,buttonEdit;
子窗體中控件:listBoxFrm2,textBoxAdd,buttonAdd,buttonEdit,buttonOK。
主窗體中還是定義類數據成員,
private ArrayList listData1;
在構造函數里實例化它,填充數據,最后綁定到listBoxFrm1。
構造函數如下:
public Form1()
{
InitializeComponent();
this.listData1 = new ArrayList();
this.listData1.Add("DotNet");
this.listData1.Add("C#");
this.listData1.Add("Asp.net");
this.listData1.Add("WebService");
this.listData1.Add("XML");
this.listBoxFrm1.DataSource = this.listData1;
}
主窗體的修改按鈕處理函數:
private void buttonEdit_Click(object sender, System.EventArgs e)
{
Form2 formChild = new Form2();
formChild.Owner = this;
formChild.ShowDialog();
this.listBoxFrm1.DataSource = null;
this.listBoxFrm1.DataSource = this.listData1;
}
我們設置了formChild.Owner為this,這樣,子窗體和主窗體就有聯系了,
當然我們也可以改成如下:
private void buttonEdit_Click(object sender, System.EventArgs e)
{
Form2 formChild = new Form2();
formChild.ShowDialog(this);
this.listBoxFrm1.DataSource = null;
this.listBoxFrm1.DataSource = this.listData1;
}
不過這樣還不行,目前主窗體的listData1變量外部訪問不到,
private ArrayList listData1;
必須修改為public訪問修飾符,
public ArrayList listData1;
也可以通過屬性(property)來實現,
public ArrayList ListData1
{
get{return this.listData1;}
}
這里我采用屬性,感覺語法更靈活,清楚。
下面是對Form2的修改,
構造函數又恢復原貌了。
public Form2()
{
InitializeComponent();
}
另外又新增了一個窗體的Load事件,在它的事件處理函數中來獲取主窗體中的數據,
private void Form2_Load(object sender, System.EventArgs e)
{
Form1 pareForm = (Form1)this.Owner;
this.listData2 = pareForm.ListData1;
foreach(object o in this.listData2)
this.listBoxFrm2.Items.Add(o);
}
有人會問,為什么不把上面的代碼放到構造函數里面去呢?如下不是更好,
public Form2()
{
InitializeComponent();
Form1 pareForm = (Form1)this.Owner;
this.listData2 = pareForm.ListData1;
foreach(object o in this.listData2)
this.listBoxFrm2.Items.Add(o);
}
那我會對你說錯了,因為在主窗體修改按鈕被點擊后,開始執行
Form2 formChild = new Form2();
而在Form2的實例化過程中會在構造函數中執行
Form1 pareForm = (Form1)this.Owner;
而這時的this.Owner是沒有值的,為空引用,那么下面的代碼肯定也出問題,
this.listData2 = pareForm.ListData1;
foreach(object o in this.listData2)
this.listBoxFrm2.Items.Add(o);
當整個Form2實例化完成后,才會執行
formChild.Owner = this;
這條代碼,所以使用了Form2_Load事件。
那怎樣可以不使用Form2_Load事件呢?等下面我們來修改代碼實現它。
下面的子窗體代碼沒有變化,
private void buttonAdd_Click(object sender, System.EventArgs e)
{
if(this.textBoxAdd.Text.Trim().Length>0)
{
this.listData2.Add(this.textBoxAdd.Text.Trim());
this.listBoxFrm2.Items.Add(this.textBoxAdd.Text.Trim());
}
else
MessageBox.Show("
請輸入添加的內容!");
}
private void buttonDel_Click(object sender, System.EventArgs e)
{
int index = this.listBoxFrm2.SelectedIndex;
if(index!=-1)
{
this.listData2.RemoveAt(index);
this.listBoxFrm2.Items.RemoveAt(index);
}
else
MessageBox.Show("
請選擇刪除項!");
}
private void buttonOK_Click(object sender, System.EventArgs e)
{
this.Close();
}
好了,結果同第一篇中的一樣,子窗體能修改主窗體的值。
2
.使用自定義屬性或方法
下面我們來講講怎樣使用自定義屬性或方法來完成數據修改功能而不使用Form2_Load事件。
主窗體的修改按鈕點擊處理函數如下:
private void buttonEdit_Click(object sender, System.EventArgs e)
{
Form2 formChild = new Form2();
formChild.ListData2 = this.listData1;
formChild.ShowDialog();
this.listBoxFrm1.DataSource = null;
this.listBoxFrm1.DataSource = this.listData1;
}
并且我們去掉了主窗體的ListData1屬性,
//public ArrayList ListData1
//{
// get{return this.listData1;}
//}
而在子窗體中加上ListData2屬性,
public ArrayList ListData2
{
set
{
this.listData2 = value;
foreach(object o in this.listData2)
this.listBoxFrm2.Items.Add(o);
}
}
也可以把屬性改成方法,
public void SetListData(ArrayList listData)
{
this.listData2 = listData;
foreach(object o in this.listData2)
this.listBoxFrm2.Items.Add(o);
}
而在主窗體的修改按鈕處理函數中也要相應改動:
formChild.ListData2 = this.listData1;
改為
formChild.SetListData(this.listData1);
總結,我們通過Form類的Owner屬性來建立主從窗體間的橋梁,這個是不是類似于把主窗體作為子窗體的構造函數參數傳入實現的功能差不多;另外又采用了屬性和方法來完成數據的交互,我覺得這種實現方法很實用,特別是用在不需要實例化類或著已經有了實例的情況下傳遞數據。
三.使用靜態類
這個也是我們經常要用到的一種數據交互方法。
這個也是我們經常要用到的一種數據交互方法。
下面是定義的一個類:
using System;
using System.Collections;
namespace ZZ
{
public class AppDatas
{
private static ArrayList listData;
static AppDatas()
{
listData = new ArrayList();
listData.Add("DotNet");
listData.Add("C#");
listData.Add("Asp.net");
listData.Add("WebService");
listData.Add("XML");
}
public static ArrayList ListData
{
get{return listData;}
}
public static ArrayList GetListData()
{
return listData;
}
}
}
上面包含了一個靜態類成員,listData,一個靜態構造函數static AppDatas(),用來初始化listData的數據。還有一個靜態屬性ListData和一個靜態GetListData()方法,他們實現了同樣的功能就是返回listData。
由于前面兩篇文章已經講了很多,這里不細說了,下面是完整的代碼:
Form1.cs文件
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
namespace ZZ
{
public class Form1 : System.Windows.Forms.Form
{
private System.Windows.Forms.Button buttonEdit;
private System.Windows.Forms.ListBox listBoxFrm1;
private System.ComponentModel.Container components = null;
public Form1()
{
InitializeComponent();
this.listBoxFrm1.DataSource = AppDatas.ListData;
}
protected override void Dispose( bool disposing )
{
if( disposing )
if(components != null)
components.Dispose();
base.Dispose( disposing );
}
[STAThread]
static void Main()
{
Application.Run(new Form1());
}
private void InitializeComponent()
{
this.buttonEdit = new System.Windows.Forms.Button();
this.listBoxFrm1 = new System.Windows.Forms.ListBox();
this.SuspendLayout();
this.buttonEdit.Location = new System.Drawing.Point(128, 108);
this.buttonEdit.Name = "buttonEdit";
this.buttonEdit.TabIndex = 1;
this.buttonEdit.Text = "修改";
this.buttonEdit.Click += new System.EventHandler(this.buttonEdit_Click);
this.listBoxFrm1.ItemHeight = 12;
this.listBoxFrm1.Location = new System.Drawing.Point(12, 8);
this.listBoxFrm1.Name = "listBoxFrm1";
this.listBoxFrm1.Size = new System.Drawing.Size(108, 124);
this.listBoxFrm1.TabIndex = 2;
this.AutoScaleBaseSize = new System.Drawing.Size(6, 14);
this.ClientSize = new System.Drawing.Size(208, 141);
this.Controls.Add(this.listBoxFrm1);
this.Controls.Add(this.buttonEdit);
this.Name = "Form1";
this.Text = "Form1";
this.ResumeLayout(false);
}
private void buttonEdit_Click(object sender, System.EventArgs e)
{
Form2 formChild = new Form2();
formChild.ShowDialog();
this.listBoxFrm1.DataSource = null;
this.listBoxFrm1.DataSource = AppDatas.ListData;
}
}
}
Form2.cs文件
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
namespace ZZ
{
public class Form2 : System.Windows.Forms.Form
{
private System.Windows.Forms.Button buttonOK;
private System.ComponentModel.Container components = null;
private System.Windows.Forms.ListBox listBoxFrm2;
private System.Windows.Forms.Button buttonAdd;
private System.Windows.Forms.Button buttonDel;
private System.Windows.Forms.TextBox textBoxAdd;
public Form2()
{
InitializeComponent();
foreach(object o in AppDatas.ListData)
this.listBoxFrm2.Items.Add(o);
}
protected override void Dispose( bool disposing )
{
if( disposing )
if(components != null)
components.Dispose();
base.Dispose( disposing );
}
private void InitializeComponent()
{
this.buttonOK = new System.Windows.Forms.Button();
this.listBoxFrm2 = new System.Windows.Forms.ListBox();
this.buttonAdd = new System.Windows.Forms.Button();
this.buttonDel = new System.Windows.Forms.Button();
this.textBoxAdd = new System.Windows.Forms.TextBox();
this.SuspendLayout();
this.buttonOK.Location = new System.Drawing.Point(188, 108);
this.buttonOK.Name = "buttonOK";
this.buttonOK.TabIndex = 0;
this.buttonOK.Text = "確定";
this.buttonOK.Click += new System.EventHandler(this.buttonOK_Click);
this.listBoxFrm2.ItemHeight = 12;
this.listBoxFrm2.Location = new System.Drawing.Point(8, 8);
this.listBoxFrm2.Name = "listBoxFrm2";
this.listBoxFrm2.Size = new System.Drawing.Size(168, 124);
this.listBoxFrm2.TabIndex = 2;
this.buttonAdd.Location = new System.Drawing.Point(188, 44);
this.buttonAdd.Name = "buttonAdd";
this.buttonAdd.TabIndex = 3;
this.buttonAdd.Text = "增加";
this.buttonAdd.Click += new System.EventHandler(this.buttonAdd_Click);
this.buttonDel.Location = new System.Drawing.Point(188, 76);
this.buttonDel.Name = "buttonDel";
this.buttonDel.TabIndex = 4;
this.buttonDel.Text = "刪除";
this.buttonDel.Click += new System.EventHandler(this.buttonDel_Click);
this.textBoxAdd.Location = new System.Drawing.Point(188, 12);
this.textBoxAdd.Name = "textBoxAdd";
this.textBoxAdd.Size = new System.Drawing.Size(76, 21);
this.textBoxAdd.TabIndex = 5;
this.textBoxAdd.Text = "";
this.AutoScaleBaseSize = new System.Drawing.Size(6, 14);
this.ClientSize = new System.Drawing.Size(272, 141);
this.Controls.Add(this.textBoxAdd);
this.Controls.Add(this.buttonDel);
this.Controls.Add(this.buttonAdd);
this.Controls.Add(this.listBoxFrm2);
this.Controls.Add(this.buttonOK);
this.Name = "Form2";
this.Text = "Form2";
this.ResumeLayout(false);
}
private void buttonOK_Click(object sender, System.EventArgs e)
{
this.Close();
}
{
this.Close();
}
private void buttonAdd_Click(object sender, System.EventArgs e)
{
if(this.textBoxAdd.Text.Trim().Length>0)
{
AppDatas.ListData.Add(this.textBoxAdd.Text.Trim());
this.listBoxFrm2.Items.Add(this.textBoxAdd.Text.Trim());
}
else
MessageBox.Show("請輸入添加的內容!");
}
private void buttonDel_Click(object sender, System.EventArgs e)
{
int index = this.listBoxFrm2.SelectedIndex;
if(index!=-1)
{
AppDatas.ListData.RemoveAt(index);
this.listBoxFrm2.Items.RemoveAt(index);
}
else
MessageBox.Show("請選擇刪除項!");
}
}
}
總結,我認為使用靜態類比較多的地方就是把應用程序的配置文件裝載到一個靜態類里面,讓所有的窗體和其他實例都可以通過靜態屬性以及靜態方法使用這些數據,比如三層結構或多層結構都可以訪問它,而不是在多個實例間傳來傳去。在這里我們討論的是Windows窗體,其實在兩個不同的實例間交互數據,都可以采用三篇文章中的方案實現,除非是這個類特有的屬性或著方法?,F在都講完了,雖然不是什么高深的東西,但是希望能對一些初學者有所幫助,同時也歡迎各位朋友進行技術交流,共同提高。
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
