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();  //子窗口获得焦点
}

这样,就能够如我们如愿般调用子窗口了。

URL:http://blog.csdn.net/cybernewer/article/details/2944570

原文地址:https://www.cnblogs.com/asdyzh/p/9902520.html

时间: 2024-08-02 13:39:55

C# WinForm:无法访问已释放的对象的相关文章

(转)C#在父窗口中调用子窗口的过程(无法访问已释放的对象)

C#在父窗口中调用子窗口的过程: 1. 创建子窗口对象 2. 显示子窗口对象 笔者的程序中,主窗体MainFrm通过菜单调用子窗口ChildFrm.在窗体中定义了子窗口对象,然后在菜单项点击事件中,加入了如下代码来创建和显示子窗口: Private childFrm myChildFrm = null; //定义子窗口对象 private void OpenChildFrmToolStripMenuItem_Click(object sender, EventArgs e) { myChildF

C# Socket连接 无法访问已释放的对象

在进行Socket长连接时,若服务器或客户端出现异常时,另外一端对Socket对话进行操作时,程序会出现无法访问已释放的对象的问题.例如客户端出现问题主动断开Socket时,当服务器操作Socket时,比如主动断开Socket会话,那么程序会出现“无法方位已释放的对象”,是由于客户端的原因导致服务器和客户端的Socket已经不存在或连接已经断开,即Socket已经释放,服务器再操作服务器和客户端的Socket肯定会报错,因此在服务器或客户端一侧操作Socket时,必须首先判断Socket是否存在

异步Udp监听关闭 出现异常,访问已释放的资源或者其他错误的解决方法

在开发异步Udp程序的过程中,通常在关闭UDP的时候回遇到诸如socket 访问已释放的资源之类的异常,如下简单操作下: 1 Udp的监听 2 this.serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); 3 this.serverSocket.SetSocketOption(SocketOptionLevel.Socket,SocketOptionName.Reus

WdatePicker 没有权限 不能执行已释放 Script 的代码

提示 拒绝访问 或 没有权限 或 ' Window.document 或 '$dp' 为空或不是对象 $dp.dd is undefined 之类的错误 SCRIPT70: 没有权限 WdatePicker.jsSCRIPT5011: 不能执行已释放 Script 的代码 解决方法: 下载最新版本下载1: http://files.cnblogs.com/my97/My97DatePicker.7z下载2: http://files.cnblogs.com/my97/My97DatePicker

Entity Framework 出现 "此 ObjectContext 实例已释放,不可再用于需要连接的操作" 的错误

原因 Entity的导航属性在View中使用,但是该Entity所在的Context已经在Controller中通过 using 释放掉:但是Entity又具有Deferred Query Evaluation性质,因此,导航属性对象没有被加载,从而出现上述错误. 解决方案 解决方法一:How to: Explicitly Load Related Objects 禁用Context的Deferred Query Evaluation,然后在查询结束后手动加载所有需要的导航属性 context.

IE 不能执行已释放script的代码

从Dom中删除IFrame后,IE9+会回收内存.影响范围:适用于 Internet Explorer 9 以及更高版本. 场景(相当隐蔽!!!): 在主页面定义一个全局变量,然后让子页面IFrame内的操作去更新这个值. 1 //主页面 2 top.G_config = {}; //定义了一个全局变量 1 //IFrame页面 2 3 //操作全局变量 4 if('undefined' == typeof(top.G_config['url_list'])){ 5 top.G_config['

已释放的栈内存

(被调)函数内的局部变量在函数返回时被释放,不应被外部引用.虽然并非真正的释放,通过内存地址仍可能访问该栈区变量,但其安全性不被保证.后续若还有其他函数调用,则其局部变量可能覆盖该栈区内容.常见情况有两种:前次调用影响当前调用的局部变量取值(函数的"遗产"):被调函数返回指向栈内存的指针,主调函数通过该指针访问被调函数已释放的栈区内容(召唤亡灵). 1 函数的"遗产" [示例1]先后连续调用Ancestor和Sibling函数,注意函数内的dwLegacy整型变量.

SCRIPT5011:不能执行已释放Script的代码

环境:win7 64位 IE9 错误:SCRIPT5011:不能执行已释放Script的代码. 现象:在父窗体的close()中调用嵌套的iframe页面的js方法返回一个对象时抛此异常. 原因:在一个iframe中定义对象,在这个iframe被删除后,方法执行的环境丢失,就会报这个错误 我的解决办法:直接在父窗体定义对象,在子窗体中调用父窗体中定义的对象并赋值.

.net开发Ae释放com对象的问题

本文转载自: http://www.cnblogs.com/yhlx125/archive/2011/11/22/2258543.html#2269154我的博文 http://www.cnblogs.com/tendzzss/archive/2011/11/11/2245627.html ae的com对象是需要释放的,不然就可能会锁住一些基础设备(如mdb文件等),这里研究了一下ae锁mdb的情况. 释放方法一般是,Marshal.ReleaseComObject或Marshal.FinalR