Closing a form during a constructor

一世执手 提交于 2019-12-17 09:37:35

问题


Is it possible to close a form while the constructor is executing (or simply to stop it showing at this stage)?

I have the following code:

public partial class MyForm : Form
{        
    public MyForm()
    {
        if (MyFunc())
        {
            this.Close();
        }
    }
}

Which throws an ObjectDisposedException in Main(), here:

    static void Main()
    {            
        ...

        // Following line errors
        Application.Run(new MyForm());
    }

I’ve tried checking the result of MyForm like this:

static void Main()
{            
    ...

    MyForm frm = new MyForm();
    if (frm != null)
    {
        // Following line errors
        Application.Run(frm);
    }
}

But that doesn’t seem to help. Can anyone tell me a way around this, please? Maybe a way to check the form to see if it still exists?


回答1:


Calling Close from the constructor of the Form is not possible, as it will call Dispose on a Form that has not yet been created. To close the Form after construction, assign an anonymous event handler to the Load event that closes your Form before it is displayed for the first time:

public partial class MyForm : Form
{
    public MyForm()
    {
        if (ShouldClose())
        {
            Load += (s, e) => Close();
            return;
        }

        // ...
    }

    // ...
}



回答2:


The only thing you could do it set a flag to close it in the constructor, and then closing it in the Shown event. Of course, if you're doing that, it makes sense to move the code to determine whether it should be closed there in the first place.




回答3:


The following works well:

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();
    }
}



回答4:


When you call Close() on a form, internally it is disposing of the form and releasing any managed resources. When you do this:

Application.Run(new MyForm());

You'll likely get an ObjectDisposedException. What you need to do is set the Form's visibility through a property:

Application.Run(new MyForm() { Visible = false });

Just make sure you remove the call to Close() in the constructor, or even move the property assignment there too.




回答5:


Can you make MyFunc static? and then do something like:

static void Main() 
{             
    ... 
    if (MyForm.MyFunc())
    {
        Application.Run(new MyForm()); 
    }
} 

this would essentially give you the same control over whether the form is going to be constructed or not?




回答6:


I found adding a handler to the 'Load' event is better as this way the dialog is never displayed at all. With the 'Shown' event you might briefly see the dialog open and then close which may be confusing:

public partial class MyForm : Form
{        
    public MyForm()
    {
        if (MyFunc())
        {
            this.Load += MyForm_CloseOnStart;
        }
    }

    private void MyForm_CloseOnStart(object sender, EventArgs e)
    {
        this.Close();
    }
}



回答7:


Environment.Exit(...) is working for me (without window flickering):

public partial class MyForm : Form
{        
    public MyForm()
    {
        if (weShouldClose)
        {
            Environment.Exit(0);
        }
    }
}



回答8:


I think it is not wise to close a form in the constructor. If you do this, users of your form wouldn't know whether to ShowDialog or not.

The following code would be quite normal use:

// in the parent form:
public void ShowMyForm()
{
    MyForm form = new MyForm();
    form.propertyA = ...;
    from.propertyB = ...;
    DialogResult dlgResult = form.ShowDialog(this);
    ProcessDialogResult(dlgResult);
}

If you decided in the constructor whether the Form ought to be shown, you would have to add code after construction to decide whether to call ShowDialog or not and whether to Process the dialog result.

Furthermore, are you sure that changing the properties will never influence whether the form is to be shown or not? Also after future changes?

During construction the form is not shown / opened yet. So I'm afraid Close() doesn't do what you expect.

The neat method is to do the checks that you wanted to do in the constructor in the Form_Load. Add an event handler for form-load and do your checks in the event handler. Use the property DialogResult to indicate that you decided not to show the form.

private void FormMain_Load (object sender, EventArgs e)
{
    if (FormShouldNotLoad())
    {
        this.DialogResult = System.Windows.Forms.DialogResult.Abort;
        Close();
        // Warning, this does not work, see below, (but we're almost there!)
    }
}

The user of the code could check the result of the dialog:

// 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.Abort:
            ProcessFormNotLoaded();
            break;
        case System.Windows.Forms.DialogResult.OK:
            ProcessFormOk();
            break;
        // etc.
    }
}

However, calling Close() in the event handler for form-load won't work, because Close() can only be called properly after Load is completed.

Therefore, instead of calling Close(), you should BeginInvoke the Close() function, so the Close function will be called after loading is done:

private void FormMain_Load (object sender, EventArgs e)
{
    if (FormShouldNotLoad())
    {
        this.DialogResult = System.Windows.Forms.DialogResult.Abort;
        // invoke the Close function after Load completed
        this.BeginInvoke(new MethodInvoker( () => this.CancelLoading())
    }
}



回答9:


If you want your window to never be seen
(no flickering windows that open for an instant and then disappear):

public new void Show()
{
    if (MyFunc())
        base.Show();
    else
        ; // dispose or whatever
}

Though Show(...) has 2 overloads and ShowDialog(...) has 2 too.
Doesn't work for the main form that is opened via Application.Run(). But who would do that anyways? Except there is also a way to open main form without using Application.Run().



来源:https://stackoverflow.com/questions/3067901/closing-a-form-during-a-constructor

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!