Closing all forms in an application seems like it would be a simple task of using a foreach loop in the Application.OpenForms collection, such as:
foreach (Form form in Application.OpenForms) { form.Close(); }
But there are two problems.
First, the code above will throw an exception because the OpenForms collection changes each time you close a form, and so the enumerator in your foreach loop becomes invalid when you close a form. Instead, you need to get an array of all open forms, then loop through the array:
static public void CloseAllForms() { // get array because collection changes as we close forms Form[] forms = OpenForms; // close every open form foreach (Form form in forms) { CloseForm( form ); } }
Second, it’s quite possible that your application opened one or more forms in a separate thread. If so, then trying to close a form from your main thread will throw an exception. So you need to close your forms in a thread-safe manner:
delegate void CloseMethod( Form form ); static private void CloseForm( Form form ) { if (!form.IsDisposed) { if (form.InvokeRequired) { CloseMethod method = new CloseMethod( CloseForm ); form.Invoke( method, new object[] { form } ); } else { form.Close(); } } }
Download a C# WinForms project that demonstrates how to close all Forms in a C# application in a thread-safe manner.
Awesome, thanks!
Learned something new!
Sound good but this statement doesn’t pass the compiler
Form[] forms = OpenForms;
I get an error said can not implicitly convert Applicaton form collection to System.Windows.Forms
Yes, I see how that can be confusing. OpenForms in the second example is a static method that I wrote which returns an array of open forms (versus Application.OpenForms which returns a collection). Download the example, but here is the code:
public static Form[] OpenForms
{
get
{
Form[] forms = null;
int count = Application.OpenForms.Count;
forms = new Form[count];
if (count > 0)
{
int index = 0;
foreach (Form form in Application.OpenForms)
{
forms[index++] = form;
}
}
return forms;
}
}
its a lot more simple to just use the FormCollection, since that is what Application.OpenForms uses
FormCollection forms = Application.OpenForms;
for( int i = 0; i < forms.Count; i++ ) {
forms[i].Close();
}
Ryan, if you read the article, that doesn’t work because closing the form modifies the collection, which then throws an exception while iterating.
Thanks, i was having trouble closing a form created on a separate thread and this has solved it!
I Guess this code is very simple compare to the above solutions.
public static void CloseAllForms()
{
//Create a Collection to Store all Opened Forms.
List formsList = new List();
//All all opened forms into a Collection.
foreach (Form frm in Application.OpenForms)
{
//Execulde the Current Form.
if (frm.Name == “Form1”)
continue;
else
formsList.Add(frm);
}
//Now Close the forms
foreach (Form frm in formsList)
{
frm.Close();
}
}
I don’t think this solution is thread-safe either. Think about what happens if Application.OpenForms is modified by another thread opening or closing a form, while the static OpenForms property’s get accessor is iterating through the foreach statement? The OpenForms collection would be altered between iterations of the foreach, which causes a runtime exception. Similar problems plague a simple for statement.
If you want true thread safety, then the OpenForms property will need to be wrapped in a lock(Application.OpenForms) statement. Any other places in your application that open or close a form will likewise need to lock the same object.
Nice article… n learn a nice technique.
[…] Second, it’s quite possible that your application opened one or more forms in a separate thread. If so, then trying to close a form from your main thread will throw an exception. So you need to close your forms in a thread-safe manner: view source […]
This is a modified version of one of the above, might be useful to someone.
Public Sub CloseAllForms()
‘Create a Collection to Store all Forms.
Dim FormList As ArrayList = New ArrayList()
‘Add all opened forms into a Collection.
For Each Frm In Application.OpenForms
FormList.Add(Frm.name)
Next
‘Now Close the forms
For Each FormName In FormList
Application.OpenForms(FormName).Close()
Next
End Sub
Ryan’s change looks more promising, although I’m not sure what exactly happens when creating a FormCollection (does it simply make a reference to Application.OpenForms or does it copy it? And does the operation behind that copy also have the same problem?)
The static OpenForms function runs based on a foreach loop of Application.OpenForms itself, which can be changed via other means during its cycle. You’re creating a second array, which is good, but the process used to create the second list is also vulnerable to a form closing during its execution.
My situation is different from just doing a window cleanup, though. I’m using it in threads to check and see if program was closed so the threads don’t cause it to hang. They check often so once in a great while my program runs into this exception.
It is working nice. great!…
how about close dialog boxes? opened by the forms? 🙂
Its working fine
This thread helped me.. thanks a lot..
I am having a issue where I cannot close a Form that has a dialog error message box on top of a form.
When I try using the .Close() method on the form it also does not close the form because it still has a open dialog on top of it.
So when I do a (Application.OpenForms) it does not show the message box form as part of the count.
Think it relates to Kirill question:
‘how about close dialog boxes? opened by the forms? :)’
I ended up using .Dispose() instead of .Close() and this seemeed to get ride of the Dialog box infront of my Form.
By the way I wanted to close all open forms except my main form. This is when the issue occured.
List forms = new List(Application.Forms)
for (int index = 0; index < forms.count; ++index)
{
if !(forms(index) is me)
{
forms(index).Dispose()
} // End if
} // End for
I think this is much simpler than using an array. Little more expensive. But many times more manageable.
I agree with using .Dispose() over .Close(). I'm not sure if it invokes the same events as .Close() does. Which means Form.Closing/form.Closed might not run? Just depends if you are handing those events or not (or they may still run, untested).
List forms = new List(Application.Forms)
Sorry. In dumb vb mindset at the moment 😉
List forms = new List(Application.Forms)
for (int index = 0; index < forms.count; ++index)
{
if !(forms(index) is me)
{
forms(index).Dispose()
} // End if
} // End for
Try this once more. It was parsing my comment like html.
Try this way:
void CloseAllMenuItemClick(object sender, EventArgs e)
{
if(Application.OpenForms.Count > 1)
{
Application.OpenForms[1].Close();
CloseAllMenuItemClick(null, null);
}
}
like it……………..
This really helped. Application.OpenForms(i).Close worked for me. Thanks
It was great! It helped me alot!
just change the:
Form[] forms = OpenForms;
to –>
Form[] forms = Application.OpenForms.Cast().ToArray();
Thanks