C# WinForm:無法訪問已釋放的物件
阿新 • • 發佈:2018-11-03
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”。
{
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(); //子視窗獲得焦點
} 這樣,就能夠如我們如願般呼叫子視窗了。 URL: http://blog.csdn.net/cybernewer/article/details/2944570
private void OpenChildFrmToolStripMenuItem_Click(object sender, EventArgs e)
{
myChildFrm = new ChildFrm();//建立子視窗物件
myChildFrm.Show();//顯示子視窗
} 當點選選單中的OpenChild項時,建立了子視窗並顯示在最前面。此時如果關閉子視窗再點選選單開啟,不會有問題。但是如果子視窗沒有關閉的情況下,再次點選選單中的OpenChild項,則會再建立一個子視窗。兩個子視窗具有相同的內容,這不是我們所希望看到的。 為此,對選單項點選事件做如下改進:
{
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(); //子視窗獲得焦點
} 這樣,就能夠如我們如願般呼叫子視窗了。 URL: http://blog.csdn.net/cybernewer/article/details/2944570