C # GUI обрабатывает проблемы при закрытии - PullRequest
0 голосов
/ 18 апреля 2009

Я получаю ошибку System.InvalidOperationException, когда я закрываю свое приложение до завершения поиска. Когда я закрываю Form1_FormClosing, я говорю всем темам прервать. В одном потоке он имеет finalize, который вызывает делегатскую функцию, которая сообщает одному из элементов управления в форме изменить свой текст. Когда это происходит, я получаю исключение выше вместе с «Дополнительная информация: Invoke или BeginInvoke не могут быть вызваны для элемента управления, пока не будет создан дескриптор окна».

Что я могу сделать, чтобы исправить это? Я мог бы добавить флаг isClosing и проверить его перед обновлением текста, но это похоже на взлом и маскировку проблемы. Как мне правильно решить эту проблему?

Ответы [ 2 ]

1 голос
/ 18 апреля 2009

Я согласен с Самуилом, но также проверю IsDisposed:

void Handler()
{
  if (ctrl.IsDisposed || !ctrl.IsHandleCreated) return;
  if (ctrl.InvokeRequired) 
    Invoke(...);
  else {
    ...
  }
}
1 голос
/ 18 апреля 2009

Это происходит из-за того, что управляемый элемент управления удален и у него больше нет дескриптора, но вы еще не закрыли окно, поэтому вы все еще видите его.

Вы можете создать функцию, которая обернет вызов Invoke и проверит наличие IsHandleCreated перед вызовом Invoke. Если IsHandleCreated ложно, вы не можете позвонить Invoke и просто проигнорировать вызов.

public static class ControlExtensions
{
  public static TResult InvokeEx<TControl, TResult>(this TControl control,
                                          Func<TControl, TResult> func)
    where TControl : Control
  {
    if (!control.IsHandleCreated)
      return default(T);

    if (control.InvokeRequired)
      return (TResult)control.Invoke(func, control);
    else
      return func(control);
  }

  public static void InvokeEx<TControl>(this TControl control,
                                        Action<TControl> action)
    where TControl : Control
  {
    control.InvokeEx(c => { action(c); return c; });
  }
}

Так что теперь просто оберните все Invoke s из ваших потоков с помощью InvokeEx, и он будет обрабатывать, когда элемент управления был удален и больше не имеет дескриптора.

this.InvokeEx(c => c.label1.Text = "Hello world");
...