2010-10-25 4 views
4

J'essaie d'afficher des informations sur une grille interrogée à partir d'un serveur sql. La collecte de données peut prendre environ 10 secondes, donc je ne veux pas verrouiller le thread de l'interface utilisateur.Erreur lors de l'appel lorsque le formulaire est déjà fermé

J'ai actuellement code comme:

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; 
     }); 
    } 
} 

Cela fonctionne la plupart du temps en dehors de si la forme est sur est fermé avant la mise à jour terminée, il se bloque avec l'erreur:

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

Je comprends que l'erreur sera due au fait que le formulaire n'existe plus alors lorsque la section finally essaie d'invoquer la méthode sur le thread de l'interface utilisateur, elle ne le peut pas.

Y a-t-il une meilleure façon de faire tout cela? Je suppose que je peux gérer les erreurs d'invocation, mais il semble malpropre et je pense que j'ai probablement manqué un moyen plus simple.

Répondre

4

Vous pouvez vérifier si le formulaire a été fermé et ne pas l'invoquer si le formulaire a été fermé. if (this.IsHandleCreated) devrait fonctionner. Cela peut cependant encore poser problème car le formulaire peut être fermé entre le chèque et l'appel au BeginInvoke. La seule solution «complète» est alors d'entourer l'appel entier dans un try/catch.

+0

ou this.IsHanleCreated –

+0

@Dmitry: * 'IsHandleCreated', n'est-ce pas? – abatishchev

+0

Oui, ça devrait marcher aussi. –

1

Essayez d'utiliser InvokeRequired() avant Invoke()

1

Invoke utilise un WinForms spécial SynchronizationContext dans les coulisses que vous pouvez accéder avec SynchronizationContext.Current partout dans votre application.

CORRECTION après un camouflet à réflecteur: en fait Invoke va la voie directe de triage via PostMessage, il est le BackgroundWorker qui utilise SynchronizationContext dans les coulisses. Invoke lancera s'il n'a pas de handle de fenêtre.

Fondamentalement, vous devez le stocker dans une variable avant de démarrer le thread, par ex. alors que vous êtes toujours dans votre thread d'interface utilisateur et utilisez la méthode Post ou Send du contexte dans le code du thread. Ce faisant, le matériel sera correctement assemblé sans poignées de fenêtre.

Questions connexes