C# WinForm:無法訪問已釋放的對象


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();  //子窗口獲得焦點
}
 
 
 
這樣,就能夠如我們如願般調用子窗口了。
 
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM