Closing a form during a constructor

C#WinformsConstructor

C# Problem Overview


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?

C# Solutions


Solution 1 - C#

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

        // ...
    }

    // ...
}

Solution 2 - C#

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.

Solution 3 - C#

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

Solution 4 - C#

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.

Solution 5 - C#

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?

Solution 6 - C#

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

Solution 7 - C#

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

Solution 8 - C#

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

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

Solution 9 - C#

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().

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionPaul MichaelsView Question on Stackoverflow
Solution 1 - C#ChristianView Answer on Stackoverflow
Solution 2 - C#ErikHeemskerkView Answer on Stackoverflow
Solution 3 - C#diveinyouView Answer on Stackoverflow
Solution 4 - C#Matthew AbbottView Answer on Stackoverflow
Solution 5 - C#MauroView Answer on Stackoverflow
Solution 6 - C#Headers13View Answer on Stackoverflow
Solution 7 - C#Harald CoppoolseView Answer on Stackoverflow
Solution 8 - C#PollitzerView Answer on Stackoverflow
Solution 9 - C#BitterblueView Answer on Stackoverflow