Закрытие или скрытие форм приводит к ошибке перекрестного потока - PullRequest
4 голосов
/ 17 февраля 2010

Я озадачен этой простой задачей, которую я выполняю снова и снова.

У меня есть массив дочерних форм. Массив инициируется в конструкторе другой формы:

frmChildren = new ChildGUI[20];

Когда пользователь запрашивает дочернюю форму, я делаю это:

if (frmChildren[nb] == null)
{
    frmChildren[nb] = new ChildGUI();
    frmChildren[nb].MdiParent = this.MdiParent;
}
frmChildren[nb].Show();

Пока это работает . В фоновом режиме я могу загрузить новый контент для этих форм. Когда загрузка закончена, я запускаю событие ChildChange. Вот где он перестает работать. Я просто хочу закрыть / скрыть все открытые формы, а затем создать новый набор -frmChildren = new ChildGUI [20]; - вот одно из многих испытаний:

        for (int i = 0; i < frmChildren.Length;i++ )
        {
            if (frmChildren[i] != null)
            {
                //frmChildren[i].BeginInvoke(new EventHandler(delegate
                //{
                    frmChildren[i].Close();
                //}));
            }
        }             
        frmChildren= new ChildGUI[20];

Я получаю исключение Cross Thread для .Close (). Обратите внимание, что я уже пытался выполнить вызов, но по какой-то причине он обходит! = Null. Я думаю, что это может иметь какое-то отношение к сборщику мусора. У кого-нибудь есть вход?

1 Ответ

9 голосов
/ 17 февраля 2010

Проблема в том, что ваш анонимный метод захватывает i - поэтому к тому моменту, когда фактически вызывается в потоке пользовательского интерфейса, вы получаете другое значение i, которое может быть нулевым , Попробуйте это:

for (int i = 0; i < frmChildren.Length; i++)
{
    ChildGUI control = frmChildren[i];
    if (control != null)
    {
        control.BeginInvoke(new EventHandler(delegate
        {
            control.Close();
        }));
    }
}             
frmChildren = new ChildGUI[20];

См. сообщение в блоге Эрика Липперта о том, почему введение новой переменной в цикл устраняет проблему.

РЕДАКТИРОВАТЬ: Если вы хотите использовать цикл foreach, это будет выглядеть так:

foreach (ChildGUI control in frmChildren)
{
    // Create a "new" variable to be captured
    ChildGUI copy = control;
    if (copy != null)
    {
        copy.BeginInvoke(new EventHandler(delegate
        {
            copy.Close();
        }));
    }
}             
frmChildren = new ChildGUI[20];

Кроме того, вы можете использовать тот факт, что вы просто хотите вызвать метод void, чтобы сделать код немного проще. Поскольку при этом больше не используется анонимный метод, вы можете обойтись без «внутренней» переменной:

foreach (ChildGUI control in frmChildren)
{
    if (control != null)
    {
        control.BeginInvoke(new MethodInvoker(control.Close));
    }
}             
frmChildren = new ChildGUI[20];
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...