C#中通過父視窗調用子視窗的問題
來源:互聯網
上載者:User
C# 在父視窗中調用子視窗的過程: 1、 建立子視窗對象 2、 顯示子視窗對象 筆者的程式中,主表單MainFrm通過菜單調用子視窗ChildFrm。在表單中定義了子視窗對象,然後在功能表項目點擊事件中,加入了如下代碼來建立和顯示子視窗: Private childFrm myChildFrm = null ; // 定義子視窗對象
private void OpenChildFrmToolStripMenuItem_Click( object sender, EventArgs e)
... {
myChildFrm = new ChildFrm();//建立子視窗對象
myChildFrm.Show();//顯示子視窗
myChildFrm.Focus();//使子視窗獲得焦點
} 當點擊菜單中的OpenChild項時,建立了子視窗並顯示在最前面。此時如果關閉子視窗再點擊菜單開啟,不會有問題。但是如果子視窗沒有關閉的情況下,再次點擊菜單中的OpenChild項,則會再建立一個子視窗。兩個子視窗具有相同的內容,這不是我們所希望看到的。 為此,對功能表項目點擊事件做如下改進: private void OpenChildFrmToolStripMenuItem_Click( object sender, EventArgs e)
... {
if(myChildFrm != null)
...{
myChildFrm.Show();//顯示子視窗
myChildFrm.Focus();//使子視窗獲得焦點
}
else
...{
myChildFrm = new ChildFrm();//建立子視窗對象
myChildFrm.Show();//顯示子視窗
myChildFrm.Focus();//使子視窗獲得焦點
}
}
這樣修改的目的是:當子視窗對象存在時,直接顯示子視窗。當子視窗不存在時,建立子視窗,然後再顯示。 現在來檢驗效果:當第一次點擊OpenChild功能表項目時,建立子視窗並正確顯示。不關閉子視窗的情況下再點擊OpenChild功能表項目,子視窗只顯示了一個,說明按預期工作了。現在,我們關閉子視窗,再點擊OpenChild功能表項目,程式在運行到下面這個語句時出現“未處理 ObjectDisposedException”異常。 if(myChildFrm != null) { myChildFrm.Show();// 顯示子視窗 錯誤資訊:無法訪問已釋放的對象。對象名:“childFrm”。 這就讓人奇怪了。如果子視窗沒有被銷毀,那它就應該能夠正確顯示。點擊了關閉子視窗,顯然應該子視窗已經銷毀了,按理myChildFrm等於null,啟動並執行時候應該直接運行else後面的語句塊,為什麼卻進入了滿足myChildFrm!=null的語句塊呢。 其實,這個問題與C#的記憶體回收有關。記憶體回收行程管理所有的託管對象,所有需要管理的資料的.NET語言(包括 C#)都受運行庫的記憶體回收行程的制約。記憶體回收行程可以確定運行記憶體回收的最佳時間,自動進行記憶體回收。然而記憶體回收的一個產物是:C#對象沒有確定性毀壞。所以會出現子視窗對象已被銷毀,但又不為null,故出現訪問時產生“未處理 ObjectDisposedException”異常(來自於“從小處看C#.net記憶體回收”一文)。 如何解決這個題,有人提出:應該應該徹底回收Child所佔的資源。並提供瞭解決方法(請搜尋“從小處看C#.net記憶體回收”查看相關情況)。 其實,現在我們需要解決的問題僅僅是:
子視窗已經被銷毀,但對象卻不為null。只需要對你視窗中的菜單點擊事件函數進行簡單修改就可以了。 private void OpenChildFrmToolStripMenuItem_Click( object sender, EventArgs e)
... {
if(myChildFrm != null)
...{
if(myChildFrm.IsDisposed)
myChildFrm = new ChildFrm();//如果已經銷毀,則重新建立子視窗對象
myChildFrm.Show();
myChildFrm.Focus();
}
else
...{
myChildFrm = new ChildFrm();
myChildFrm.Show();
myChildFrm.Focus();
}
}
前面這是按邏輯的方式進行思考的,顯示子視窗和獲得焦點兩行是重複的,兩個if語句也可以做一下簡化。指定子視窗和父視窗的父子關係。最後的結果是這樣: private void OpenChildFrmToolStripMenuItem_Click( object sender, EventArgs e)
... {
if(myChildFrm == null || myChildFrm.IsDisposed)
...{
myChildFrm = new ChildFrm();
}
myChild..MdiParent = this; //建立父子關係
myChildFrm.Show(); //顯示子視窗
myChildFrm.Focus(); //子視窗獲得焦點
} 這樣,就能夠如我們如願般調用子視窗了。 附