Accueil .Net / C# / WPF / Silverlight Tutoriaux WPF WPF - Mise à jour GUI - Thread

WPF - Mise à jour GUI depuis un Thread


Il est souvent très difficile de mettre à jour notre interface graphique durant des tâches annexes surtout depuis qu'il n'existe plus la méthode Application.DoEvents() en WPF (sauf si on fait un import System.Windows.Form.dll).

Prenons un exemple, nous avons un StackPanel qui doit contenir les tâches en cours d'exécution, et un autre processus qui enchaine les tâches les unes après les autres. Comment mettre à jour le StackPanel à chaque changement d'étape?

Pour répondre à ce problème il suffit d'utiliser la technique suivante : le DispatcherFrame de la librairie  :
- Une DispatcherFrame provenant de la librairie System.Windows.Threading,
- Et le Dispatcher courant.


1/ Mise à jour de mon StackPanel

using System;
using System.Windows.threading;
....

private void updateMessageUI(String text)
{
   DispatcherFrame frame = new DispatcherFrame();
   Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Render, new DispatcherOperationCallback(delegate(object parameter)
   {

     /// Mon objet graphique qui doit être empilé dans mon StackPanel
     taskElement _elem = new taskElement();
     _elem.taskTexte.Text = text;
     this._taskTache.Children.Add(_elem);
     _elem = null;
     frame.Continue = false;
     return null;
  }), null);
  Dispatcher.PushFrame(frame);
}


...

Ne pas oublier de mettre le frame.Continue à false, sinon cette tâche sera en exécution prolongée.

 
2/ Refaire le DoEvents avec un DispatcherFrame (merci à [ Audrey PETIT ])

public class WpfApplication : Application
{
   private static DispatcherOperationCallback exitFrameCallback = new

   DispatcherOperationCallback(ExitFrame);

   /// <summary>
   /// Processes all UI messages currently in the message queue.
   /// </summary>

   public static void DoEvents()
   {
      // Create new nested message pump.

      DispatcherFrame nestedFrame = new DispatcherFrame();

      // Dispatch a callback to the current message queue, when getting called,
      // this callback will end the nested message loop.
      // note that the priority of this callback should be lower than the that of UI event messages.

      DispatcherOperation exitOperation = Dispatcher.CurrentDispatcher.BeginInvoke(
      DispatcherPriority.Background, exitFrameCallback, nestedFrame);

      // pump the nested message loop, the nested message loop will
      // immediately process the messages left inside the message queue.

      Dispatcher.PushFrame(nestedFrame);

      // If the "exitFrame" callback doesn't get finished, Abort it.

      if (exitOperation.Status != DispatcherOperationStatus.Completed)
      {
         exitOperation.Abort();
      }
   }

   private static Object ExitFrame(Object state)
   {
      DispatcherFrame frame = state as DispatcherFrame;

      // Exit the nested message loop.

      frame.Continue = false;
      return null;
   }

}
}

Mise à jour le Mercredi, 28 Octobre 2009 11:18