2010-08-06 4 views
2

HI,erreur BeginInvoke

Ce quetion est dans le prolongement de ma question à this link.

j'ai écrit une demande de comparer l'approche, qui y est utilisé, avec d'autres moyens. Lors de l'exécution de l'application en mode débogage j'ai eu l'erreur "Invoke ou BeginInvoke ne peut pas être appelé sur un contrôle jusqu'à ce que le handle de fenêtre a été créé." sur le premier BeginInvoke dans la méthode UpdateCustDetails. Bien que, il ne donne aucune erreur d'exécution lors de l'exécution du code sans débogage. Des idées??

Merci, Abhi.

Voici mon code: -

public delegate void UpdateLabelDelegate(Label lb, string text); 
public delegate void loadCustomersDelegate(); 

public partial class Form1 : Form 
{ 
    public Form1() 
    { 
     InitializeComponent(); 

     loadCustomersDelegate del = new loadCustomersDelegate(UpdateCustDetails); 
     IAsyncResult ar = del.BeginInvoke(null, null); 

     while (!ar.IsCompleted) 
     { 
     } 

    } 

    public void updateLabel(Label lb, string text) 
    { 

     lb.Text = text; 

    } 

    public void UpdateCustDetails() 
    { 
     BeginInvoke(new UpdateLabelDelegate(updateLabel), new object[] { label1, "Test" }); 
     BeginInvoke(new UpdateLabelDelegate(updateLabel), new object[] { label2, "Test1234" }); 
     BeginInvoke(new UpdateLabelDelegate(updateLabel), new object[] { label3, "Test5678" }); 
     BeginInvoke(new UpdateLabelDelegate(updateLabel), new object[] { label4, "Test0000" }); 
    } 
} 
+0

@ 366436 abhi où habitez-vous en Inde –

+0

Salut Steven, je suis d'origine indienne, mais je suis basé au Royaume-Uni actuellement. –

+1

Essayez de déplacer le code du constructeur Form1 vers onload-event du formulaire. (Sauf provoquer l'appel InitializeComponents). – Alxandr

Répondre

1

Tout d'abord, il y a quelques choses que je dirais à propos de la structure du code affiché qui pourrait aider.

Qu'est-ce que le code fait est ceci:

  • Dans le constructeur pour Form1, de manière asynchrone invoque une méthode (sur un thread différent)
  • Cette méthode invoque de manière asynchrone quatre appels à une méthode distincte pour mettre à jour les contrôles d'étiquettes . Les invoque sont poussés vers le thread d'interface utilisateur (le fil que nous étions dans le constructeur de Form1)
  • Le constructeur, quant à lui, attend la méthode originale pour terminer avant de poursuivre

Il y a un certain nombre de niaiseries dans ce code:

  • Une méthode est invoquée de manière asynchrone (de manière non bloquante), puis le code attend son achèvement. À moins qu'il y ait une raison impérieuse pour que ce code soit sur un thread d'arrière-plan, pourquoi ne pas simplement appeler la méthode de manière synchrone à la place? Cela laissera le même comportement mais rendra le débogage et la lecture du code beaucoup plus faciles.
  • En raison de la boucle while attente sur ar.IsCompleted, vous trouverez que le thread d'interface utilisateur est en fait assez occupé - marteler la CPU sur cette boucle vide, au lieu de rester inactif et permettant des fils de fond de fonctionner. Je soupçonne qu'appeler la méthode de manière synchrone serait plus performant.
  • Parce que UpdateCustDetails utilise BeginInvoke, il va envoyer les quatre appels asynchrones et retourner immédiatement. Cela signifie que - même si le constructeur attend ar.IsCompleted - vous avez aucune garantie que les étiquettes seront mises à jour au moment où le constructeur se termine - parce que les quatre appels à updateLabel ne bloquent pas.
  • En fait, parce que Form.BeginInvoke coups de pied exécution retour au thread d'interface utilisateur de la forme, ce que vous faites vraiment est le coup d'envoi d'un fil d'arrière-plan juste pour lancer le travail au thread qui l'a créé.

Donc en bref: ignorer l'erreur, sortez tous les trucs de fil intelligent à la recherche, et faire ceci:

public partial class Form1 : Form 
{ 
    public Form1() 
    { 
     InitializeComponent(); 

     UpdateCustDetails(); 
    } 

    public void updateLabel(Label lb, string text) 
    { 
     lb.Text = text; 
    } 

    public void UpdateCustDetails() 
    { 
     updateLabel(label1, "Test"); 
     updateLabel(label2, "Test1234"); 
     updateLabel(label3, "Test5678"); 
     updateLabel(label4, "Test0000"); 
    } 
} 

Vous obtiendrez le même résultat, avec de meilleures performances et plus code lisible.

+0

Salut Dan, J'aurais fait la même chose si j'avais écrit le même code moi-même, mais je veux faire fonctionner ce code et voir ce qu'il fait et si possible le comparer avec l'approche normale du bon sens. En fait ce code fait partie d'une application que nous avons sur notre système et je suis supposé le maintenir à l'avenir. :-(Et croyez-moi, l'application est remplie de codes "intelligents" comme celui-ci Pourriez-vous s'il vous plaît me conseiller comment faire ce code de travail afin que je puisse le comparer avec diverses autres approches. savoir quoi ne pas faire et pourquoi Merci, Abi –

+0

J'ai réussi à faire fonctionner le code et je n'ai pas été surpris de voir que l'approche normale était l'approche la plus efficace par rapport à l'approche BeginInvoke. –

Questions connexes