在我們的程式中,表單之間經常要相互訪問彼此的成員,調用彼此的方法,或者激發彼此的事件。下面就我的經驗,簡單談談在.NET中表單間相互訪問的幾種方式。以下給出了C#.NET和VB.NET的範例程式碼。用Form1、Form2類分別表示主、從表單。
1、內部成員訪問法,適合於主表單訪問它所建立的從表單對象中的成員。只需將從表單允許主表單訪問的那些成員加上internal或Friend限定符。例如:
C#主 |
private void ShowForm2Info() { Form2 f2 = new Form2(); f2.Show(); MessageBox.Show(f2.MyName); } |
C#從 |
internal string MyName = "A Form2 Object"; |
VB主 |
Private Sub ShowForm2Info() Dim f2 As New Form2 f2.Show() MsgBox(f2.MyName) End Sub |
VB從 |
Friend MyName As String = "A Form2 Object" |
2、將以上方法反過來用,讓從表單訪問建立它的主表單中的成員,需要增加一個步驟:在從表單的建構函式中傳入一個主表單的引用,以便找到建立它的主表單(建立的建構函式中不要忘了調用InitializeComponent()函數)。主表單建立從表單對象時傳入自身的引用。例如:
C#主 |
private void ShowForm2() { Form2 f2 = new Form2(this); f2.Show(); } internal string MyName = "A Form1 Object"; |
C#從 |
private Form1 f1; public Form2(Form1 _f1) { InitializeComponent(); f1 = _f1; } private void ShowForm1Info() { MessageBox.Show(f1.MyName); } |
VB主 |
Private Sub ShowForm2() Dim f2 As New Form2(Me) f2.Show() End Sub Friend MyName As String = "A Form1 Object" |
VB從 |
Private f1 As Form1 Public Sub New(ByVal _f1 As Form1) MyBase.New() InitializeComponent() f1 = _f1 End Sub Private Sub ShowForm1Info() MsgBox(f1.MyName) End Sub |
註:我的朋友wuzhenzhi指出,對主表單的引用,通過屬性或方法傳入要比通過在建構函式中傳入好,因為“對於一個表單,沒什麼,但如果是一個使用者控制項,我們經常會像拖動Button控制項一樣從工具列裡拽下來,這時系統就會調用預設的那個建構函式,而不是你的那個重載版本,這辦法就失靈了。”這個建議有道理。
3、從表單訪問主表單中的成員,如果主表單只有一個執行個體,或者被訪問對象是全域性的,可以將主表單中要求訪問的成員設定為靜態,加上static或Shared限定符即可:
C#主 |
private void ShowForm2() { Form2 f2 = new Form2(); f2.Show(); } internal static string MyName = "A Form1 Object"; |
C#從 |
private void ShowForm1Info() { MessageBox.Show(Form1.MyName); } |
VB主 |
Private Sub ShowForm2() Dim f2 As New Form2() f2.Show() End Sub Friend Shared MyName As String = "A Form1 Object" |
VB從 |
Private Sub ShowForm1Info() MsgBox(Form1.MyName) End Sub |
4、還可以運用.NET的事件委託機制,實現更加靈活的相互調用。下例是從表單激發主表單的事件。事件委託機制的功能事實上遠比此例強大,大家可以找書看看它的詳細用法。
C#主 |
private void ShowForm2() { Form2 f2 = new Form2(); f2.Show(); f2.SendMessage += new Form2.DelegateOfSendMessage(ShowMessage); } private void ShowMessage(string str) { MessageBox.Show(str); } |
C#從 |
public delegate void DelegateOfSendMessage(string str); public event DelegateOfSendMessage SendMessage; private void Send() { SendMessage("A Message From Form2"); } |
VB主 |
Private Sub ShowForm2() Dim f2 As New Form2 f2.Show() AddHandler f2.SendMessage, AddressOf ShowMessage End Sub Private Sub ShowMessage(ByVal str As String) MsgBox(str) End Sub |
VB從 |
Public Delegate Sub DelegateOfSendMessage(ByVal str As String) Public Event SendMessage As DelegateOfSendMessage Private Sub Send() RaiseEvent SendMessage("A Message From Form2") End Sub |
5、同樣的道理,參考方法2和方法4可以實現主表單激發從表單的事件,這個請讀者自己實驗。當然這樣一來代碼會顯得比較亂。一個較好的解決方案是將事件封裝入一個介面,同時在事件的發布方和訂閱者實現。這種技術在.NET Remoting遠程對象操作技術中尤為重要,有一篇不錯的文章給大家參考:《Remoting事件處理全接觸》(http://www.cnblogs.com/wayfarer/articles/75213.html)
6、習慣了VB6中全域變數的朋友可能覺得.NET中不支援全域變數對於表單間的互動很不方便,那麼再請大家參考這篇文章:《.NET表單之間的互動》(http://blog.csdn.net/warsgrobe/archive/2005/07/29/438013.aspx),裡面敘述了用VB.NET類比全域變數的方法。另外我的朋友wuzhenzhi提出了在全域模組中建立全域變數解決方案,大家可以參考他的文章:《對預設啟動表單操作的方法》(http://wuzhenzhi.blogdriver.com/wuzhenzhi/875776.html)
7、本文發布的第二天,wuzhenzhi提醒我:事實上.NET中有一個現成的方法讓從表單訪問主表單的成員,就是帶有owner參數的Form.ShowDialog方法。這個owner便是對主表單的引用。這個快捷的方法適合於對話方塊性質的從表單(也就是說在操作從表單時不允許操作主表單),但對諸如MDI子表單等不適用。注意owner是個IWin32Window,需要強制轉化為主表單類。
C#主 |
private void ShowForm2() { Form2 f2 = new Form2(); f2.ShowDialog(this); } internal string MyName = "A Form1 Object"; |
C#從 |
private void ShowForm1Info() { MessageBox.Show(((Form1)(this.Owner)).MyName); } |
VB主 |
Private Sub ShowForm2() Dim f2 As New Form2() f2.ShowDialog(Me) End Sub Friend MyName As String = "A Form1 Object" |
VB從 |
Private Sub ShowForm1Info() MsgBox(CType(Me.Owner, Form1).MyName) End Sub |
8、那麼對於MDI子表單有什麼好方法呢?最怕的就是看了上面的幾種方法,形成思維定勢,直接就套用了。須知矛盾有普遍性,也有特殊性,對於MDI子表單照樣有現成的方法,就是調用子表單的MdiParent屬性訪問主表單。這個想必大家都知道,放在這裡,保持文章的完整性。
C#主 |
private void ShowForm2() { Form2 f2 = new Form2(); f2.MdiParent = this; f2.Show(); } internal string MyName = "A Form1 Object"; |
C#從 |
private void ShowForm1Info() { MessageBox.Show(((Form1)(this.ParentForm)).MyName); } |
VB主 |
Private Sub ShowForm2() Dim f2 As New Form2 f2.MdiParent = Me f2.Show() End Sub Friend MyName As String = "A Form1 Object" |
VB從 |
Private Sub ShowForm1Info() MsgBox(CType(Me.ParentForm, Form1).MyName) End Sub |
OK,就說到這裡。.NET是一個強大而靈活的體系,只要肯動腦筋,一定能發現不少這樣的技巧。