標籤:

C#WinForm窗體之間的相互操作

程序員在.Net平台下進行WinForm應用程序開發過程中,經常會遇到窗體之間的相互傳值或者其他的調用操作,這是在.Net平台上編寫WinForm程序很重要的一個基礎,網路上問及這方面的帖子特別多,我做了簡單舉例並將具體的方法做了一個總結。  設計如下的兩個窗體:

  From1中button1的功能代碼相對簡單:  Form2 Frm2 = new Form2();  Frm2.Show();  Form2.textbox1.text=textbox1.text;     在輸入最後的代碼時有問題,系統會提示「窗體調用.Form2」並不包含「textbox1」的定義」,看From2中的定義文件中,有「private System.Windows.Forms.TextBox textBox1;」說明Form2窗體中的textbox1是私有的,對外不能訪問,怎麼辦?改動訪問屬性,將「Private」改為「internal」(即在本程序集里可以訪問)再運行,系統正常了。  總結:可以通過改變窗體控制項的訪問屬性來進行操作。  系統將窗體控制項的訪問屬性默認為私有,這樣做是遵循了面向對象的封裝原則,所以,我們還是將「internal」改回「Private」,那上面的問題怎麼解決?  既然是打開窗體就傳值,那麼在From2中聲明一個構造函數就然後在From2窗體初始化的時候就傳值就可以了,在From2中聲明新的構造函數:  public Form2(string SValue)  { this.textBox1.Text = SValue;  }  在From1窗體的button1按鈕的點擊事件中寫如下代碼:  Form2 Frm2 = new Form2(textBox1.Text);  Frm2.Show();  代碼沒有問題,運行時系統報告構造函數錯誤,原來From2(string SValue)的textbox1對象為空,那麼就是說該代碼運行於初始化事件之前【在窗體或者控制項繪製圖形或者其他操作時也會遭遇這樣的問題,即在對象初始化之前進行類似操作當然會出現問題】,所以改動代碼如下:  public Form2(string SValue)  { InitializeComponent();//加入初始化事件 this.textBox1.Text = SValue;  }  運行,系統正常了。  總結:可以定義一個傳遞對象並且在窗體的構造函數中接收傳遞對象來處理窗體的傳值操作。  現在處理Form1中的button2事件,它的作用是在Form2窗體打開的情況下改變該窗體中的textbox1的值。  寫代碼時必須找到打開的窗體然後再賦值,因為對Frm2定義只在button1_Click方法體中存在,所以無法在本方法體中利用Frm2,那麼是不是在把Frm2的作用域延伸到整個Form1窗體(在Form1中定義)就可以利用Frm2了。但是這個沒有解決問題,關鍵在於Form2中的textbox1是私有的,所以,我們沒有必要在Form1中定義對Form2的引用。  找到目前打開的Form2窗體的實例對象,可以應用Application對象,它包含了一個集合對象OpenForms,通過檢索它可以找到目前打開的窗體。  textbox1 既然是私有的,那麼我們可以通過定義屬性來操作它,如下:  public string Textbox1  { get { return textBox1.Text; } set { textBox1.Text = value; }  }  那麼Form1中的button2的點擊事件代碼可以這樣寫了:  ((Form2)Application.OpenForms["Form2"]).Textbox1 =textBox1.Text;  運行系統,正常。  問題又來了,當你打開多個Form2實例對象窗體時,上面的代碼只改變最先打開的那個,其他的沒有反應。  因為Application.OpenForms["Form2"])是按Form2名稱檢索【索引器】,檢索到後就返回了,所以只有最先打開的Form2對象接收了操作,改動Form1中的button2的點擊事件代碼如下:  foreach (Form Frm in Application.OpenForms)  { if (Frm.Text == "Form2") { ((Form2)Frm).Textbox1 = textBox1.Text; }  }  這樣就可以對所有打開的Form2對象實例進行相同的操作了。www.it165.net  總結:根據封裝原則,通過屬性來封裝對象內的欄位操作提高安全性,檢索Application.OpenForms可以對系統目前打開的窗體進行操作。  窗體傳值是一個事件的改變觸發另外一個方法或者動作,對於此類應用我們一般通過委託來實現。  在Form2中寫下如下代碼:  public delegate void MyDelegateChange(string Str);//定義委託  public MyDelegateChange MyChange;//聲明  //定義動作  private void MyChangeFunction(string Str)  { textBox1.Text = Str;  }  在Form2的button2的點擊事件中寫下如下代碼:  MyChange = new MyDelegateChange(MyChangeFunction);  在Form1的button2的點擊事件中寫下如下代碼:  Form2 Frm2 = new Form2();  foreach (Form Frm in Application.OpenForms)  { if (Frm.Text == "Form2") { Frm2 = (Form2)Frm; }  }  Frm2.MyChange(textBox1.Text);  運行系統,正常傳值。  我們還可以通過委託定義事件來處理。  在Form2中寫下入下代碼:  public delegate void MyDelegateChange(string Str);//定義委託  public event MyDelegateChange OnMyChange;//聲明事件  public void Form2_OnMyChange(string Str)  { //事件動作 textBox1.Text = Str;  }  在Form1的button2的點擊事件中寫下如下代碼:  Form2 Frm2 = new Form2();  Frm2.Form2_OnMyChange(textBox1.Text);  運行,系統正常傳值。  總結:可以通過委託和事件來進行窗體之間的傳值操作。  其實,上面是秉承面向對象的原則來處理,看起來麻煩,如下方法可以隨意地達到目的:  Form Frm2 = new Form2();  foreach (Form Frm in Application.OpenForms)  { if (Frm.Text == "Form2") { Frm2 = Frm; }  }  Frm2.Controls["textbox1"].Text = textBox1.Text;  在寫代碼過程中,通過上面的方式我們只能操作控制項共有的屬性和方法,如果是控制項特有的,可以通過引用的方式進行處理,假設Form2上面有個CheckBox1的控制項,現在在Form1的Button2的點擊事件中操作它,可以按如下的方式:  CheckBox CB1=new CheckBox();  CB1 = Frm2.Controls["checkBox1"] as CheckBox;  CB1.Checked = true;  比如,現在Form2窗體上有個名為button1的按鈕,你希望觸發它的點擊事件,可以這樣寫:  ((Button)Frm2.Controls["button1"]).PerformClick();  總結:我們可以通過檢索集合對象來進行窗體之間相互靈活的操作。  網路上,對於對話框窗口的傳值的問題也很多,解決辦法是如果你想獲取一個窗口的返回值,直接調用就可以。  當然也可以通過如下方法來調用,比如在Form1中打開了Form2,點擊Form2上面的按鈕更改Form1上面的textBox1的值,可以如下寫:  this.Owner.Controls[「textbox1」].text=」123」;  另外,我們還可以通過API的調用來進行窗體之間的相互操作,只是現在已沒有必要這樣去做了。

本文出自 「我愛編程」 博客


推薦閱讀:

TAG:Form |