J'ai fait quelques recherches et je ne peux pas vraiment trouver un moyen préféré de faire la mise à jour des contrôles de formulaire à partir d'un thread de travail en C#. Je connais le composant BackgroundWorker, mais quelle est la meilleure façon de le faire sans utiliser le composant BackgroundWorker? Pourquoi ne voulez-vous pas le faire en utilisant BackgroundWorker?Quel est le meilleur moyen de mettre à jour les contrôles de formulaire à partir d'un thread de travail?
Répondre
Il existe une règle générale qui stipule de ne pas mettre à jour l'interface utilisateur à partir d'un thread autre que le thread d'interface utilisateur lui-même. Utiliser les fonctionnalités de BackgroundWorker est une bonne idée, mais vous ne voulez pas et quelque chose se passe sur un thread différent, vous devriez faire un "Invoke" ou BeginInvoke pour forcer le délégué à exécuter la méthode sur le thread UI.
Edit: Jon B fait ce bon point dans les commentaires:
Gardez à l'esprit que Invoke() est synchrone et BeginInvoke() est asynchrone. Si vous utilisez Invoke(), vous devez faire attention à ne pas provoquer un interblocage . Je recommanderais BeginInvoke() à moins que vous ayez vraiment besoin de que l'appel soit synchrone.
Certains code simple exemple:
// Updates the textbox text.
private void UpdateText(string text)
{
// Set the textbox text.
m_TextBox.Text = text;
}
public delegate void UpdateTextCallback(string text);
// Then from your thread you can call this...
m_TextBox.Invoke(new UpdateTextCallback(this.UpdateText),
new object[]{"Text generated on non-UI thread."});
Le code ci-dessus est d'une FAQ à ce sujet here et plus impliquer davantage un here.
Il a un événement de rappel fantastique appelé ProgressChanged qui permet au thread UI de connaître les mises à jour, parfait pour les mises à jour de type barre de progression et ainsi de suite.
Je considérerais également InvokeRequired (VS2008 uniquement) lors de l'appel Invoke. Il y a des moments où vous ne serez pas mettre à jour l'interface utilisateur à partir d'un fil séparé. Il économise le temps de création du délégué, etc.
if (InvokeRequired)
{
//This.Invoke added to circumvent cross threading exceptions.
this.Invoke(new UpdateProgressBarHandler(UpdateProgressBar), new object[] { progressPercentage });
}
else
{
UpdateProgressBar(progressPercentage);
}
Que fait exactement le m_TextBox.Invoke? Cela force-t-il le délégué à être exécuté sur le thread de l'interface utilisateur? – Yttrium
Exactement. Gardez à l'esprit que Invoke() est synchrone et BeginInvoke() est asynchrone. Si vous utilisez Invoke(), vous devez faire attention à ne pas provoquer un blocage. Je recommanderais BeginInvoke() à moins que vous ayez vraiment besoin que l'appel soit synchrone. –
Bon appel, Jon B. J'aurais dû le mentionner. Je vais modifier pour refléter le point. –