Закройте все открытые формы, кроме главного меню В C#

попытка закрыть все формы, кроме главного меню, используя

FormCollection formsList = Application.OpenForms;

С петлей foreach и говоря,

if (thisForm.Name != "Menu") thisForm.Close();

который работает нормально, он пропускает меню и закрывает первый, но затем ошибки:

коллекция была изменена; операция перечисления может не выполняться

и останавливается. Я пробовал несколько мест, и все они говорят, что этот цикл foreach-это способ сделать это, и это особенно раздражает, поскольку я не обновление списка форм после закрытия форм, что, как я думал, может сработать. Единственное, что я мог придумать, это начать и работу через некоторое время.

8 ответов


Если вы используете foreach для перечисления через коллекцию, ее нельзя изменить (элементы добавлены или удалены) во время итерации. Попробуйте скопировать ссылки на формы в другую коллекцию, а затем удалить их путем итерации по этой коллекции.

в таких ситуациях вы можете использовать список или простой массив, например:

List<Form> openForms = new List<Form>();

foreach (Form f in Application.OpenForms)
    openForms.Add(f);

foreach (Form f in openForms)
{
    if (f.Name != "Menu")
        f.Close();
}

или вы можете использовать цикл for:

for (int i = Application.OpenForms.Count - 1; i >= 0; i--)
{
    if (Application.OpenForms[i].Name != "Menu")
        Application.OpenForms[i].Close();
}

или, мой новый и текущий любимый, Вы можете использовать обратный() метод:

foreach (Form f in Application.OpenForms.Reverse())
{
    if (f.Name != "Menu")
        f.Close();
}

это происходит, когда коллекция изменяется внутри цикла foreach, который ее использует. Вы удаляете элемент из formsList внутри цикла.

попробуйте это:

for (int i = formsList.Count-1; i > 0; i--)
{
    if (formsList[i].Name != "Menu")
    {
        formsList[i].Close();
    }
}

вот еще более краткий метод, который использует то же количество строк, что и ваш исходный метод:

Form[] forms = Application.OpenForms.Cast<Form>().ToArray();
foreach (Form thisForm in forms)
{
    if (thisForm.Name != "Menu") thisForm.Close();
}

используя метод расширения Linq Cast, вы можете избежать цикла через коллекцию для создания массива.


закрыть все формы :

        for (int i = Application.OpenForms.Count - 1; i >= 0; i--)
        {
            if (Application.OpenForms[i].Name != "Menu")
                Application.OpenForms[i].Close();
        }

как говорится в сообщении об ошибке, вы не можете изменить коллекцию в ее foreach.

вместо этого вы можете использовать backwards for петли.


поскольку коллекция форм обновляется для каждой итерации. При закрытии формы она удаляется из коллекции форм. это похоже на удаление объекта из памяти во время его использования .


коллекция была изменена; операция перечисления может не выполняться.

FormCollection formsList = Application.OpenForms;
            //for (int i = 0; i < formsList.Count; i++)
            foreach(Form  f in formsList )
            {
                if (f.Name != "Form1" || f.Name != "Home" || f.Name != "AdminHome")
                    f.Close();
            }
            this.Close();

Я знаю, что это старый, но мне нужно было выполнить этот же сценарий и придумать элегантный и простой способ достичь этого следующим образом

        Form[] formsList = Application.OpenForms.Cast<Form>().Where(x => x.Name == "Form1").ToArray();
        foreach (Form openForm in formsList)
        {                
            openForm.Close();
        }

это закроет все окна, которые, где открылись, называются Form1