Traitement fenêtre d'attente modale sans Thread

by Nicolas Calvi 17. juin 2008 13:08
Parfois on aimerait bien afficher une fenêtre d'attente pendant un long traitement et que celle-ci soit affichée dans le contexte de notre application, le plus souvent en mode modale. Cependant si on exécute ce code :
using ( MaFormAttente oForm = new MaFormAttente() )
{
  // On affiche la fenêtre d'attente
  oForm.Show();
  // On effectue le traitement qui justifie la mise en attente
  MaFonctionDeTraitement();
}
La fenêtre d'attente va bien s'afficher mais elle n'est pas liée à la Form d'avant, elle n'est pas modale. Cela veut dire que l'utilisateur peut cliquer ailleurs et ainsi masquer la fenêtre d'attente. Ceci n'est pas très ergonomique. Si on affiche la fenêtre d'attente en mode modale :
using ( MaFormAttente oForm = new MaFormAttente() )
{
  // On affiche la fenêtre d'attente
  oForm.ShowModal(this);
  // On effectue le traitement qui justifie la mise en attente 
  MaFonctionDeTraitement(); 
}
Cela pose problème car l'exécution va s'arrêter sur le ShowModal et on doit attendre la fermeture de la fenêtre pour reprendre le traitement, or ce n'est pas ce que nous voulons. Ce qui serait intéressant, c'est de pouvoir invoquer le ShowModal et faire exécuter le contenu de MaFonctionDeTraitement dans celle-ci. Dans ce cas nous aurions bien la fenêtre d'attente en mode modale et l'exécution du traitement, tout cela sans utiliser de Thread.

La solution que je vous propose est de créer une méthode anonyme et l'exécuter dans la fenêtre modale, à la fin de l'exécution nous pourrions récupérer un résultat de la méthode anonyme. Voici donc comment faire :

Première étape : Créer un délégué pour l'exécution

J'ai choisi de créer un délégué afin d'envoyer le traitement à la fenêtre modale. Ce délégué permet d'avoir une valeur retour à la fin de l'exécution de la tâche. On le type en Object comme ça on peut renvoyer tout type d'objet.

public delegate object MonDelegueModal();

Deuxième étape : Créer une fenêtre d'attente

Il faut maintenant définir la fenêtre modale qui va accueillir le traitement et mettre en attente l'utilisateur. Pour cela, nous ajoutons une Form à notre projet. Dans cette Form nous allons définir deux variables membres, une pour stocker la référence de la méthode anonyme à exécuter et une autre pour stocker le retour de la méthode. Nous allons aussi redéfinir le constructeur afin de pouvoir passer la méthode anonyme et ajouter un accesseur pour récupérer le retour de la méthode anonyme. Ensuite sur l'événement Shown nous allons invoquer notre traitement, ce qui laisse le temps à la fenêtre de s'instancier. Voici le code correspondant :

public class MaFormAttente: Form
{
  private object m_oResultat;
  private MonDelegueModal m_oMonTraitement;

  public MaFormAttente(MonDelegueModal p_oTraitement)
  {
    this.m_oResultat = null;
    this.m_oMonTraitement = p_oTraitement;
  }

  private void MaFormAttente_Shown(object sender, EventArgs e)
  {
    this.m_oResultat = this.m_oMonTraitemen();
    this.Close();
  }

  public object Resultat
  {
    get { return(this.m_oResultat); }
  }
}
Ainsi la fenêtre va pouvoir s'ouvrir en modale et lancer l'exécution de notre méthode anonyme. Une fois le traitement terminée, la fenêtre se ferme et on récupère le résultat avec l'accesseur Resultat.

Troisième étape : Appel de notre fenêtre avec une méthode anonyme

Il ne reste plus qu'a appeler notre fenêtre dans notre code. Pour cela il suffit de définir une méthode anonyme sur le modèle MonDelegueModal, d'afficher la fenêtre d'attente et de récupérer le retour.

string sTexte = "Appel méthode anonyme en modale";

// Création de la méthode anonyme
MonDelegueModal oTraitement = new MonDelegueModal(delegate
{
  MessageBox.Show(sTexte);
  return ("Terminée");
});

// Affichage de la fenêtre d'attente qui va exécuter la méthode anonyme
using ( MaFormAttente oWait = new MaFormAttente(oTraitement) )
{
  // Ouverture modale de la fenêtre
  oWait.ShowDialog(this);
  
  // Récupération du retour du traitement
  MessageBox.Show((string)oWait.Resultat);
}
Voilà ! Votre traitement est bien exécuté et une fenêtre d'attente modale est affichée. N'hésitez pas à me poser des questions.