2 July 2011

Closing all open forms in .NET

In your application you may have many hidden forms which you must close before exiting the application. It's because, hidden forms always stay in the memory until you close them. But, .net framework always takes care of disposing off all those objects when the application is terminated. But, the real problem comes when those hidden forms contain COM/ActiveX components. You all know, you must manually clean all unmanaged components. Now, if you forget to close such forms, it may lead to memory leaks.

It's very simple to close all such open forms. Application.OpenForms is the collection that contains all open forms. So, just loop through this collection and close one by one. Below is the code, where I am closing all open forms in main form's FormClosing event handler.


    private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
    {
        foreach (Form openForm in Application.OpenForms)
        {
            openForm.Close();
        }
    }

On first look, this code looks to be fine. But, there are two potential problems with this code.
First,Application.OpenForms contains your main form because it is also open currently. So, when the loop executes, it will call Close() on MainForm, which in-turn will fire FormClosing event of MainForm. This will results in calling MainForm_FormClosing method recursively and infinitely which leads to deadlock. So, a StackOverFlowException will occur. To avoid this, you can add a check as below.


    private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
    {
        foreach (Form openForm in Application.OpenForms)
        {
            if (openForm != this)
            {
                openForm.Close();
            }
        }
    }

simple, isn't it? Is it good to go now? No. Still there is a problem. To understand the problem, let us consider, we have 3 open forms. So, Application.OpenForms collection contains 3 items (say in following order)

   1. MainForm
   2. SubForm1
   3. SubForm2

Ok. The loop executes first time and skips the Close() since the condition fails. During second loop, it closes the SubForm1 and imporatantly SubForm1 is removed from Application.OpenForms collection. This means the collection is altered. Now, during 3rd loop, it tries to access the collection, an 'InvalidOperationException' is thrown saying "Collection was modified; enumeration operation may not execute". Hence, what you can do is instead of directly accessing Application.OpenForms, store all open forms in an array or a list. Then loop through the array/List and close the forms. So, below is the final code.


    private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
    {
        List<Form> lstOpenForms = Application.OpenForms.OfType<Form>().ToList();

        foreach (Form openForm in lstOpenForms)
        {
            if (openForm != this)
            {
                openForm.Close();
            }
        }
    }


I hope this information was useful.

8 comments:

  1. Great thoughts you got there, believe I may possibly try just some of it throughout my daily life.
    Best Devops Training in pune
    Devops Training in Bangalore
    Power bi training in Chennai

    ReplyDelete
  2. Really nice experience you have. Thank you for sharing. It will surely be an experience to someone.
    python Course in Pune
    python Course institute in Chennai
    python Training institute in Bangalore

    ReplyDelete
  3. Attend The Python training in bangalore From ExcelR. Practical Python training in bangalore Sessions With Assured Placement Support From Experienced Faculty. ExcelR Offers The Python training in bangalore.
    python training in bangalore

    ReplyDelete
  4. Great post. keep sharing such a worthy information.
    AWS Training institute in Chennai

    ReplyDelete