2010-11-10 5 views
0

Je développe une application Windows avec des formulaires Windows vsNET 2010 et C#. Cette application dispose d'un contrôle utilisateur qui interroge un service (WCF hébergé sur le service win) et doit le faire sans bloquer l'interface utilisateur. Le contrôle utilisateur contient une grille qui montrera les résultats. Je pense que ma situation est la plus commune. Ma question à vous est ce qui peut être fait avec C# afin que le code suivant fonctionne plus lisse et avec une meilleure gestion des erreurs. J'utilise MehtodInvoker, donc je peux éviter d'écrire deux méthodes séparées pour ce scénario call-wait-fill.Meilleures pratiques en matière d'appels asynchrones

public void LoadData() 
{ 
    StartWaitProgress(0); 
    ThreadPool.QueueUserWorkItem(x => 
    { 
     try 
     { 
      MyDocMail[] mails; 
      var history = Program.NoxProxy.GetDocumentHistory(out mails, Program.MySessionId, docId); 
      this.Invoke(new MethodInvoker(delegate() 
      { 
       this.SuspendLayout(); 
       gridVersions.Rows.Clear(); 
       foreach (var item in history) 
       { 
        gridVersions.Rows.Add(); 
        int RowIndex = gridVersions.RowCount - 1; 
        DataGridViewRow demoRow = gridVersions.Rows[RowIndex]; 
        demoRow.Tag = item.Id; 
        if (gridVersions.RowCount == 1) 
        { 
         demoRow.Cells[0].Value = Properties.Resources.Document_16; 
        } 
        demoRow.Cells[1].Value = item.Title; 
        demoRow.Cells[2].Value = item.Size.GetFileSize(); 
        demoRow.Cells[3].Value = item.LastModified; 
        demoRow.Cells[4].Value = item.CheckoutBy; 
        demoRow.Cells[5].Value = item.Cotegory; 
       } 
       gridEmails.Rows.Clear(); 
       foreach (var item in mails) 
       { 
        gridEmails.Rows.Add(); 
        int RowIndex = gridEmails.RowCount - 1; 
        DataGridViewRow demoRow = gridEmails.Rows[RowIndex]; 
        demoRow.Tag = item.Id; 
        demoRow.Cells[1].Value = item.From; 
        demoRow.Cells[2].Value = item.To; 
        demoRow.Cells[3].Value = item.Date; 
       } 
       this.ResumeLayout(); 
      })); 
     } 
     catch (Exception ex) 
     { 
      Program.PopError(ex); 
      this.Invoke(new MethodInvoker(delegate() { this.Close(); })); 
     } 
     finally { this.Invoke(new MethodInvoker(delegate() { StopWaitProgress(); })); } 
    }); 
} 

Répondre

3

Il n'y a rien de mal à votre solution, bien que vous pouvez accomplir plus facilement avec BackgroundWorker. BackgroundWorker gère les exceptions de thread, appelle Invoke dans la fenêtre WPF et aide à la génération de rapports d'avancement et à l'annulation. Plus d'exemples here.

P.S. Les futures versions de C# peuvent rendre cela encore plus facile - consultez le Async CTP.

+0

Vous pouvez également nettoyer cela en utilisant Task dans le framework .NET 4. –

+0

J'ai essayé la solution BackgroundWorker en C# 2.0, mais je ne vois aucun avantage, avec BackgroundWorker je dois séparer le code en plusieurs méthodes/événements. Dans mon application il y a des cas où dans le même formulaire je fais comme 10 appels au service wcf. Pour accélérer ces appels, je dois les faire en même temps (en parallèle sur le ThreadPool), ce qui donnera 10 instances de BackgroundWorker ... Le code ci-dessus est plus compact car je peux riter une seule méthode pour chaque appel asynchrone . –

+1

Gardez à l'esprit que vous pouvez instancier BackgroundWorker par programme et utiliser des méthodes anonymes ou des expressions lambda pour gérer les événements (c'est généralement ce que je fais). La meilleure solution dépend de votre objectif final. Pouvez-vous élaborer sur ce que vous entendez par "plus lisse et avec une meilleure gestion des erreurs"? –