2010-04-08 5 views
6

J'essaie de mettre à jour une zone de texte. Je pensais que mon code d'enfilage réglerait le problème, mais ce n'est pas le cas. Quelqu'un peut-il aider avec ceci?Erreurs de multithreading en C#

new Thread((ThreadStart)delegate { txtCapacitance.Text = Math.Round(capacitance, 3).ToString(); }).Start(); 

donne l'erreur suivante:

Cross-thread operation not valid: Control 'txtCapacitance' accessed from a thread other than the thread it was created on.

Notez que tout cela est en cours de démarrage par une fonction dataReceived qui est appelée chaque fois que des données USB est reçue.

Répondre

4

Vous devriez plutôt jeter un oeil à l'aide BackgroundWorker Class

Jetez un oeil à

C# BackgroundWorker Tutorial.

+0

Cela ne résoudra pas le problème. Les travailleurs d'arrière-plan s'exécutent toujours sur un thread différent du thread d'interface utilisateur. –

+0

@Marcelo Cantos, Avez-vous lu la documentation? * Vous devez veiller à ne manipuler aucun objet de l'interface utilisateur dans votre gestionnaire d'événements DoWork. Au lieu de cela, communiquez avec l'interface utilisateur via les événements ProgressChanged et RunWorkerCompleted. * –

+0

vous avez raison; J'ai tort; mes excuses. Je l'ai confondu avec un pool de threads normal. –

6

Les objets d'interface utilisateur peuvent uniquement être appelés à partir du thread d'interface utilisateur. Cela peut être réalisé par la méthode de contrôle Invoke:

txtCapacitance.Invoke((Action)(() => { txtCapacitance.Text = Math.Round(capacitance, 3).ToString(); })); 
+0

Je reçois cette erreur: Impossible de convertir l'expression lambda en type 'System.Delegate' car ce n'est pas un type de délégué – Adam

+0

Désolé, vous devez effectuer un cast. Je l'ai réparé. –

1

mises à jour à tout élément d'interface utilisateur doit être fait sur le thread d'interface utilisateur. Vous pouvez certainement calculer votre valeur sur un autre thread, mais vous devez utiliser la méthode .Invoke(...) du contrôle pour effectuer la mise à jour.

0

essayez celui-ci

//delegate 
delegate void updateTextboxDelegate(string value); 

private void updateDisplay(string value) 
{ 
    txtCapacitance.Text = value; 
} 

//the thread 
string msg = string.empty; 
var th =new Thread(()=>{BeginInvoke(new updateTextboxDelegate(updateDisplay), msg); }); 
th.Start(); 

Espoir qui fonctionnera pour vous.

0

Vous devez vous assurer de mettre à jour textBox à partir du même thread que celui que vous avez créé.

A cet effet, créer vous-même aide de classe comme celui-ci et d'utiliser ces extensions au lieu d'utiliser de façon normale (voici quelques extensions j'ai fait pour moi-même, mais vous intéressant est changeText):

public static class ControlExtensions { 
    public static void changeStatus(this Control varControl, bool varState) { 
     if (varControl.InvokeRequired) { 
      varControl.BeginInvoke(new MethodInvoker(() => changeStatus(varControl, varState))); 
     } else { 
      varControl.Enabled = varState; 
     } 
    } 
    public static void changeText(this Control varControl, string varText) { 
     if (varControl.InvokeRequired) { 
      varControl.BeginInvoke(new MethodInvoker(() => changeText(varControl, varText))); 
     } else { 
      varControl.Text = varText; 
     } 
    } 
    public static DateTime readDateValue(this DateTimePicker varControl) { 
     if (varControl.InvokeRequired) { 
      return (DateTime) varControl.Invoke(new Func<DateTime>(() => readDateValue(varControl))); 
     } else { 
      return varControl.Value; 
     } 
    } 
    public static bool ReadStatus(this CheckBox varControl) { 
     if (varControl.InvokeRequired) { 
      return (bool) varControl.Invoke(new Func<bool>(() => ReadStatus(varControl))); 
     } 
     return varControl.Checked; 
    } 
    public static bool ReadStatus(this RadioButton varControl) { 
     if (varControl.InvokeRequired) { 
      return (bool) varControl.Invoke(new Func<bool>(() => ReadStatus(varControl))); 
     } 
     return varControl.Checked; 
    } 
    public static string readText(this Control varControl) { 
     if (varControl.InvokeRequired) { 
      return (string) varControl.Invoke(new Func<string>(() => readText(varControl))); 
     } else { 
      return varControl.Text; 
     } 
    } 
    public static bool readEnabled(this Control varControl) { 
     if (varControl.InvokeRequired) { 
      return (bool) varControl.Invoke(new Func<bool>(() => readEnabled(varControl))); 
     } else { 
      return varControl.Enabled; 
     } 
    } 

} 

Ensuite, vous l'utilisez comme ceci: txtCapacitance.changeText("new text");