81 votes

Forcer la mise à jour de l'interface graphique à partir du fil d'interface utilisateur

Dans WinForms, comment puis-je forcer une mise à jour immédiate de l'interface utilisateur à partir du thread de l'interface utilisateur ?

Ce que je fais, c'est en gros :

label.Text = "Please Wait..."
try 
{
    SomewhatLongRunningOperation(); 
}
catch(Exception e)
{
    label.Text = "Error: " + e.Message;
    return;
}
label.Text = "Success!";

Le texte de l'étiquette ne prend pas la valeur "Please Wait..." avant l'opération.

J'ai résolu ce problème en utilisant un autre fil de discussion pour l'opération, mais cela devient épineux et j'aimerais simplifier le code.

113voto

Jagd Points 2677

Au début, je me suis demandé pourquoi l'OP n'avait pas déjà marqué l'une des réponses comme étant la réponse, mais après avoir essayé moi-même et que cela n'ait toujours pas fonctionné, j'ai creusé un peu plus profondément et j'ai découvert qu'il y a beaucoup plus de choses dans ce problème que je ne l'avais d'abord supposé.

Une meilleure compréhension peut être obtenue en lisant une question similaire : Pourquoi la commande ne peut-elle pas être mise à jour/rafraîchie en cours de processus ?

Enfin, pour mémoire, j'ai réussi à mettre à jour mon étiquette en procédant comme suit :

private void SetStatus(string status) 
{
    lblStatus.Text = status;
    lblStatus.Invalidate();
    lblStatus.Update();
    lblStatus.Refresh();
    Application.DoEvents();
}

Bien que, d'après ce que j'ai compris, c'est loin d'être une approche élégante et correcte pour le faire. C'est un hack qui peut ou non fonctionner en fonction de l'activité du fil de discussion.

18voto

Scoregraphic Points 4779

Appelez Application.DoEvents() après avoir défini l'étiquette, mais vous devriez plutôt effectuer tout le travail dans un fil séparé, afin que l'utilisateur puisse fermer la fenêtre.

17voto

Dror Helper Points 15499

Appelez label.Invalidate et ensuite label.Update() - En général, la mise à jour n'intervient qu'après la sortie de la fonction courante, mais le fait d'appeler Update la force à se mettre à jour à cet endroit précis du code. À partir de MSDN :

La méthode Invalidate détermine ce qui est peint ou repeint. La méthode Update détermine quand la peinture ou le repeint se produit. Si vous utilisez les méthodes Invalidate et Update ensemble plutôt que d'appeler Refresh, ce qui est repeint dépend de la surcharge de Invalidate que vous utilisez. La méthode Update force simplement le contrôle à être peint immédiatement, mais la méthode Invalidate régit ce qui est peint lorsque vous appelez la méthode Update.

3voto

Rick2047 Points 460

Vous pouvez essayer ceci

using System.Windows.Forms; // u need this to include.

MethodInvoker updateIt = delegate
                {
                    this.label1.Text = "Started...";
                };
this.label1.BeginInvoke(updateIt);

Voyez si ça marche.

3voto

pixelgrease Points 66

Après avoir mis à jour l'interface utilisateur, lancez une tâche à exécuter avec l'opération en cours :

label.Text = "Please Wait...";

Task<string> task = Task<string>.Factory.StartNew(() =>
{
    try
    {
        SomewhatLongRunningOperation();
        return "Success!";
    }
    catch (Exception e)
    {
        return "Error: " + e.Message;
    }
});
Task UITask = task.ContinueWith((ret) =>
{
    label.Text = ret.Result;
}, TaskScheduler.FromCurrentSynchronizationContext());

Cela fonctionne dans .NET 3.5 et plus.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X