C#在构造函数中closures表单
是否有可能在构造函数正在执行时closures窗体(或仅仅是在此阶段停止显示)?
我有以下代码:
public partial class MyForm : Form { public MyForm() { if (MyFunc()) { this.Close(); } } }
在Main()中抛出一个ObjectDisposedException,在这里:
static void Main() { ... // Following line errors Application.Run(new MyForm()); }
我试过这样检查MyForm的结果:
static void Main() { ... MyForm frm = new MyForm(); if (frm != null) { // Following line errors Application.Run(frm); } }
但是这似乎没有帮助。 有谁能告诉我一个解决这个问题的方法吗? 也许一种方法来检查表单,看看它是否仍然存在?
你唯一能做的就是设置一个标志,在构造函数中closures它,然后在Shown
事件中closures它。 当然,如果你这样做,移动代码以确定是否应该在那里closures是有意义的。
从窗体的构造函数调用Close
是不可能的,因为它将调用Dispose
在尚未创build的窗体上。 要在closures窗体后build立,分配一个匿名事件处理程序的Load
事件closures您的窗体之前,它是第一次显示:
public partial class MyForm : Form { public MyForm() { if (ShouldClose()) { Load += (s, e) => Close(); return; } // ... } // ... }
以下运作良好:
public partial class MyForm : Form { public MyForm() { if (MyFunc()) { this.Shown += new EventHandler(MyForm_CloseOnStart); } } private void MyForm_CloseOnStart(object sender, EventArgs e) { this.Close(); } }
当您在窗体上调用Close()时,内部将处理表单并释放所有托pipe资源。 当你这样做:
Application.Run(new MyForm());
你可能会得到一个ObjectDisposedException。 你需要做的是通过一个属性设置窗体的可见性:
Application.Run(new MyForm() { Visible = false });
只要确保在构造函数中删除了对Close()的调用,甚至可以在那里移动属性赋值。
你可以让MyFunc静态? 然后做一些事情:
static void Main() { ... if (MyForm.MyFunc()) { Application.Run(new MyForm()); } }
这基本上会给你同样的控制,是否表格将被构build或不是?
我发现添加一个处理程序到“Load”事件是更好的,因为这种方式从来没有显示对话框。 在“显示”事件中,您可能会短暂地看到对话框打开,然后closures,这可能会令人困惑:
public partial class MyForm : Form { public MyForm() { if (MyFunc()) { this.Load += MyForm_CloseOnStart; } } private void MyForm_CloseOnStart(object sender, EventArgs e) { this.Close(); } }
您的表单不会从构造函数中打开。 你想达到什么目的?
如果closures这个表单,那么代码path将完全退出,没有明显的好处(即Application.Run将退出)。 其他人发表了关于使表单隐藏的代码,似乎更有可能。
如果你想让你的窗户永远不被看到
(没有闪烁的窗口瞬间打开,然后消失) :
public new void Show() { if (MyFunc()) base.Show(); else ; // dispose or whatever }
虽然Show(...)
有2个重载, ShowDialog(...)
也有2个。
不适用于通过Application.Run()
打开的主窗体。 但是谁呢? 除了还有一种不使用Application.Run()
的方式来打开主窗体。
我认为在构造函数中closures表单是不明智的。 如果你这样做,表单的用户不知道是否ShowDialog。
下面的代码将是非常正常的使用:
// in the parent form: public void ShowMyForm() { MyForm form = new MyForm(); form.propertyA = ...; from.propertyB = ...; DialogResult dlgResult = form.ShowDialog(this); ProcessDialogResult(dlgResult); }
你将不得不添加特殊的代码来决定是否ShowDialog和是否处理对话框的结果。
此外,您是否确定这些属性不会影响表单是否被显示? 还有未来的变化?
施工期间,表格尚未显示/打开。 所以恐怕Close()没有达到你所期望的。
整洁的方法是在Form_Load中进行检查。 添加表单加载事件处理程序,并在那个时候进行检查。 使用属性DialogResult来表明你决定不显示表单。
private void FormMain_Load (object sender, EventArgs e) { if (FormShouldNotLoad()) { this.DialogResult = System.Windows.Forms.DialogResult.Cancel; Close(); } }
代码的用户可以检查对话框的结果:
// in the parent form: public void ShowMyForm() { MyForm form = new MyForm(); form.propertyA = ...; from.propertyB = ...; DialogResult dlgResult = form.ShowDialog(this); switch (dlgResult) { case System.Windows.Forms.DialogResult.Cancel: ... break; case System.Windows.Forms.DialogResult.OK: ... break; // etc. } }
然而,这将无法正常工作,因为closures只能在加载完成后才能正确调用。 因此,不应该调用Close(),而应该BeginInvoke Close()函数,因此在加载完成后将调用Close函数:
加载完成后调用Close()的代码如下:
private void FormMain_Load (object sender, EventArgs e) { if (MyFunc()) { CancelLoading(); } } private delegate void InvokeDelegate(); private void CancelLoading() { // will cancel loading this form this.DialogResult = System.Windows.Forms.DialogResult.Cancel; this.BeginInvoke(new InvokeDelegate(CloseThisForm)); } private void CloseThisForm() { this.Close(); }
好的一点是,在OnFormClosing和OnFormClosed期间,您完全知道表单的状态:它是完全加载的,所以您在closures时知道该怎么做。