Setting a WinForms form to be hidden on startup
An overview of my preferred technique for setting a WinForms form to be hidden on startup (without the drawbacks of some of the other common approaches).

Over the years, I've had a lot of people ask me how to best set up a WinForms form to be hidden on startup. There are also quite a few StackOverflow threads on this topic. Most of the answers either end up with a form that flickers on the screen before being hidden, or a form that isn't fully loaded and then behaves strangely when it receives certain Windows messages.

This blog post will give a quick overview of what I think is the "best" way of setting up a WinForms form that is hidden on startup.

Firstly, we'll need to define a custom implementation of the ApplicationContext class. This will be set up in a way that behaves almost identically to the base ApplicationClass class. Unlike some of the solutions you'll see for this problem, we need to ensure that the Form is shown so that it's properly initialized and responds to all Windows messages in the expected way. We set its opacity to 0 before showing it so that we don't see it flicker on the screen.

/// <summary>
/// An implementation of <see cref="ApplicationContext"/>.
/// </summary>
public class CustomApplicationContext : ApplicationContext
{
    /// <summary>
    /// The main application form.
    /// </summary>
    private Form _mainForm;

    /// <summary>
    /// Initializes a new instance of the <see cref="CustomApplicationContext"/> class.
    /// </summary>
    /// <param name="mainForm">The main form of the application.</param>
    public CustomApplicationContext(Form mainForm)
    {
        _mainForm = mainForm;

        if (_mainForm != null)
        {
            // Wire up the destroy events similar to how the base ApplicationContext
            // does things when a form is provided.
            _mainForm.HandleDestroyed += OnFormDestroy;

            // We still want to call Show() here, but we can at least hide it from the user
            // by setting Opacity to 0 while the form is being shown for the first time.
            _mainForm.Opacity = 0;
            _mainForm.Show();
            _mainForm.Hide();
            _mainForm.Opacity = 1;
        }
    }

    /// <summary>
    /// Handles the <see cref="Control.HandleDestroyed"/> event.
    /// </summary>
    /// <param name="sender">The source of the event.</param>
    /// <param name="e">An <see cref="EventArgs"/> that contains the event data.</param>
    private void OnFormDestroy(object sender, EventArgs e)
    {
        if (sender is Form form && !form.RecreatingHandle)
        {
            form.HandleDestroyed -= OnFormDestroy;
            OnMainFormClosed(sender, e);
        }
    }

    /// <summary>
    /// Performs application-defined tasks associated with freeing, releasing,
    /// or resetting unmanaged resources.
    /// </summary>
    /// <param name="disposing">
    /// true if invoked from the <see cref="IDisposable.Dispose"/> method;
    /// false if invoked from the finalizer.
    /// </param>
    protected override void Dispose(bool disposing)
    {
        if (disposing)
        {
            if (_mainForm != null)
            {
                if (!_mainForm.IsDisposed)
                {
                    _mainForm.Dispose();
                }

                _mainForm = null;
            }
        }

        base.Dispose(disposing);
    }
}

Finally, we just use our new CustomApplicationContext when we call Application.Run:

Application.Run(new CustomApplicationContext(new ExampleForm()));

That's all you need. Your form should be hidden on startup, but still initialized properly and able to respond to Windows messages as required.

Hopefully this blog post helps you out.


Posted by Matthew King on 4 November 2017
Permission is granted to use all code snippets under CC BY-SA 3.0 (just like StackOverflow), or the MIT license - your choice!
If you enjoyed this post, and you want to show your appreciation, you can buy me a beverage on Ko-fi or Stripe