从Load处理程序关闭表单

Lov*_*ode 8 c# objectdisposedexception winforms

我有一种非常奇怪的行为,似乎只在一种形式上发生.

基本上我正在创建一个实例Form,并调用Show()以显示非阻塞形式.在那个表单的Load事件处理程序中,我有一些可以this.Close()在某些情况下调用的逻辑.这会关闭表单,但是Show()客户端代码中的表单方法会抛出一个ObjectDisposedException.

ObjectDisposedException的堆栈跟踪如下:

在System.Windows.Forms.Control.CreateHandle()
在System.Windows.Forms.Form.CreateHandle()
在System.Windows.Forms.Control.get_Handle()
在System.Windows.Forms.ContainerControl.FocusActiveControlInternal()
在系统.Windows.Forms.Form.SetVisibleCore(布尔值)
在System.Windows.Forms.Control.Show()
...等.

这就是我所看到的:

  1. Control.Show() 叫做
  2. 我的表格已经发布
  3. OnFormLoad方法被调用
  4. FormLoad事件处理程序被调用,这里面我打电话this.Close()
  5. OnFormClosing方法被调用
  6. FormClosing事件处理程序被调用
  7. Dispose 在我的表单和所有用户控件上调用

然后在Control.Show()方法结束的某个地方,它会尝试获取表单的句柄,这会因为对象被标记为处置而变形并抛出异常.

我真正的问题是,为什么我可以在没有例外的其他形式上完成同样的事情?这是GC问题吗?我尝试过GC.Collect()之后立即拨打电话this.Close()并没有任何区别.就像我说的那样,无论子用户控件,表单变量的范围等等,它都会在此表单上100%的时间内发生,而且绝不会在其他任何地方发生.

有任何想法吗?

RcM*_*Man 27

最好的方法:

 this.BeginInvoke(new MethodInvoker(this.Close));
Run Code Online (Sandbox Code Playgroud)

这是最简单的方法,你不会得到ObjectDisposedException


Jon*_*asW 8

我知道这是一个老问题,但似乎没有人发布obvoius答案.

你说你打电话Control.Show()然后Form.Close()然后表格是Disposed of.好吧,除非您使用MDI或使用ShowDialog正如文档所述.虽然,Close()文档的简短版本是"关闭表单",但它实际上也在某些条件下隐式处理它.

请参阅备注部分:http: //msdn.microsoft.com/en-us/library/system.windows.forms.form.close.aspx

如果您想再次显示表单.使用该Hide()方法代替Close().

希望有助于其他寻找灵魂.

而且,伙计们,不要停止搜索"我不知道为什么它有时会起作用".这就变成了有很多防御性的错误软件"我会再次调用这种方法以防万一".不好.


Lov*_*ode 6

好吧,不想回答我自己的问题,但这让我疯了,这是我见过的最难复制的错误之一.

在我的表单上,我重写了OnFormLoad和OnFormClose方法,我将表单的大小,位置和WindowState保存/恢复到注册表中.我把这个代码拿出来解决了问题.奇怪的是,我把它放回去,问题没有回来.

我终于重现了这个问题:你必须让表单完全打开,最大化它,然后关闭它,以便将Maximized状态保存到注册表中.然后当你再次打开它时,它会将它设置为Maximized,如果它在Load处理程序中关闭,它会在它关闭时尝试访问Size/Location.显然在OnFormClosing方法中访问这些值会导致表单尝试聚焦IF并且仅在表单最大化时才会聚焦,这是非法的,因为表单已被处理.

所以基本上,你不能在表单的OnFormClosing方法中访问表单显示属性,如果该表单将从它的Load事件调用Close.(除非你先检查Disposed prop)

我所知道的相当具体的Winforms智慧,但无论如何我都在写下来.