2010-10-25 4 views
4

Я пытаюсь отобразить некоторую информацию о сетке, запрошенной с сервера sql. Сбор данных может занять около 10 секунд, поэтому я не хочу блокировать поток пользовательского интерфейса.Ошибка при вызове, когда форма уже закрыта

настоящее время у меня код как:

ThreadPool.QueueUserWorkItem(DataUpdateThread, new UpdateParams(year)); 

private struct UpdateParams 
{ 
    internal string year; 

    internal UpdateParams(string year) 
    { 
     this.year = year; 
    } 
} 

private void DataUpdateThread(object state) 
{ 
    DataTable dTable = new DataTable(); 
    try 
    { 
     this.Invoke((MethodInvoker)delegate 
     { 
      //stop data editing on the grid 
      //scrolling marquee for user 
      marquee.Visible = true; 
      marquee.Enabled = true; 
      grdMain.Visible = false; 
      grdMain.DataSource = null; 
     }); 

      UpdateParams parameters = (UpdateParams)state;    
      dTable = GetData(parameters.year); 
    } 
    catch (Exception ex) 
    { 
     this.Invoke((MethodInvoker)delegate 
     { 
      //log error + end user message 
     }); 
    } 
    finally 
    { 
     this.Invoke((MethodInvoker)delegate 
     { 
      grdMain.DataSource = dTable; 
      grdMainLevel1.RefreshData(); 
      marquee.Visible = false; 
      marquee.Enabled = false; 
      grdMain.Visible = true; 
     }); 
    } 
} 

Это работает большую часть времени, за исключением, если форма его на закрывается до завершения обновления он будет врезаться с ошибкой:

Invoke or BeginInvoke cannot be called on a control until the window handle has been created.

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

Есть ли лучший способ сделать все это? Думаю, я могу справиться с ошибками invoke, но это выглядит беспорядочно, и я думаю, что я, вероятно, пропустил более простой способ.

ответ

4

Вы можете проверить, была ли форма закрыта и не делать вызов, если форма была закрыта. if (this.IsHandleCreated) должен работать. Тем не менее это может вызвать проблемы, поскольку форма может быть закрыта между проверкой и вызовом до BeginInvoke. Единственное «полнофункциональное» решение заключается в том, чтобы заключить весь вызов в try/catch.

+0

или this.IsHanleCreated –

+0

@Dmitry: * 'IsHandleCreated', правильно? – abatishchev

+0

Да, это тоже должно работать. –

1

Попробуйте использовать InvokeRequired() перед тем Invoke()

1

Invoke использует специальные WinForms SynchronizationContext за кулисами, что вы можете получить доступ с SynchronizationContext.Current в любом месте вашего приложения.

CORRECTION после некоторого тыкать в Рефлектор: на самом деле Invoke идет прямой путь сортировочного через PostMessage, это BackgroundWorker, что делает использование SynchronizationContext за кулисами. Invoke будет бросать, если у него нет дескриптора окна.

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

 Смежные вопросы

  • Нет связанных вопросов^_^