Comment puis-je faire tourner le curseur sur le curseur d’attente?

J’ai une application C # sur laquelle les utilisateurs se connectent, et parce que l’algorithme de hachage est coûteux, cela prend un peu de temps. Comment afficher le curseur Wait / Busy (généralement le sablier) à l’utilisateur pour lui faire savoir que le programme fait quelque chose?

Le projet est en C #.

Vous pouvez utiliser Cursor.Current .

 // Set cursor as hourglass Cursor.Current = Cursors.WaitCursor; // Execute your time-intensive hashing code here... // Set cursor as default arrow Cursor.Current = Cursors.Default; 

Cependant, si l’opération de hachage est vraiment longue (MSDN définit cela comme plus de 2-7 secondes), vous devriez probablement utiliser un indicateur de retour visuel autre que le curseur pour informer l’utilisateur de la progression. Pour un ensemble de directives plus approfondi, consultez cet article .

Modifier:
Comme @Am l’a souligné, vous devrez peut-être appeler Application.DoEvents(); après Cursor.Current = Cursors.WaitCursor; pour s’assurer que le sablier est réellement affiché.

Réellement,

 Cursor.Current = Cursors.WaitCursor; 

définit temporairement le curseur d’attente, mais ne garantit pas que le curseur d’attente s’affiche jusqu’à la fin de votre opération. D’autres programmes ou contrôles de votre programme peuvent facilement réinitialiser le curseur à la flèche par défaut, comme cela se produit lorsque vous déplacez la souris lorsque l’opération est toujours en cours.

Une méthode bien meilleure pour afficher le curseur d’attente consiste à définir la propriété UseWaitCursor dans un formulaire sur true:

 form.UseWaitCursor = true; 

Cela affichera le curseur d’attente pour tous les contrôles du formulaire jusqu’à ce que vous définissiez cette propriété sur false. Si vous souhaitez que le curseur d’attente soit affiché au niveau de l’application, vous devez utiliser:

 Application.UseWaitCursor = true; 

En me basant sur la précédente, mon approche préférée (car il s’agit d’une action fréquemment effectuée) consiste à insérer le code du curseur d’attente dans une classe d’assistant IDisposable afin de pouvoir l’utiliser avec () (une ligne de code), le code à l’intérieur, puis nettoyer (restaurer le curseur) après.

 public class CursorWait : IDisposable { public CursorWait(bool appStarting = false, bool applicationCursor = false) { // Wait Cursor.Current = appStarting ? Cursors.AppStarting : Cursors.WaitCursor; if (applicationCursor) Application.UseWaitCursor = true; } public void Dispose() { // Reset Cursor.Current = Cursors.Default; Application.UseWaitCursor = false; } } 

Usage:

 using (new CursorWait()) { // Perform some code that shows cursor } 

Il est plus facile d’utiliser UseWaitCursor au niveau du formulaire ou de la fenêtre. Un cas d’utilisation typique peut ressembler à ceci:

  private void button1_Click(object sender, EventArgs e) { try { this.Enabled = false;//optional, better target a panel or specific controls this.UseWaitCursor = true;//from the Form/Window instance Application.DoEvents();//messages pumped to update controls //execute a lengthy blocking operation here, //bla bla .... } finally { this.Enabled = true;//optional this.UseWaitCursor = false; } } 

Pour une meilleure expérience de l’interface utilisateur, vous devez utiliser Asynchrony à partir d’un thread différent.

Mon approche serait de faire tous les calculs dans un travailleur de base.

Puis changez le curseur comme ceci:

 this.Cursor = Cursors.Wait; 

Et dans l’événement de fin du thread, restaurez le curseur:

 this.Cursor = Cursors.Default; 

Notez que cela peut aussi être fait pour des contrôles spécifiques, donc le curseur sera le sablier seulement quand la souris est au-dessus d’eux.

OK, j’ai donc créé une méthode asynchrone statique. Cela a désactivé le contrôle qui lance l’action et modifie le curseur de l’application. Il exécute l’action en tant que tâche et attend de terminer. Le contrôle retourne à l’appelant pendant qu’il attend. Ainsi, l’application rest réactive, même lorsque l’icône occupée tourne.

 async public static void LengthyOperation(Control control, Action action) { try { control.Enabled = false; Application.UseWaitCursor = true; Task doWork = new Task(() => action(), TaskCreationOptions.LongRunning); Log.Info("Task Start"); doWork.Start(); Log.Info("Before Await"); await doWork; Log.Info("After await"); } finally { Log.Info("Finally"); Application.UseWaitCursor = false; control.Enabled = true; } 

Voici le code de la forme principale

  private void btnSleep_Click(object sender, EventArgs e) { var control = sender as Control; if (control != null) { Log.Info("Launching lengthy operation..."); CursorWait.LengthyOperation(control, () => DummyAction()); Log.Info("...Lengthy operation launched."); } } private void DummyAction() { try { var _log = NLog.LogManager.GetLogger("TmpLogger"); _log.Info("Action - Sleep"); TimeSpan sleep = new TimeSpan(0, 0, 16); Thread.Sleep(sleep); _log.Info("Action - Wakeup"); } finally { } } 

J’ai dû utiliser un enregistreur distinct pour l’action factice (j’utilise Nlog) et mon enregistreur principal écrit sur l’interface utilisateur (une zone de texte enrichi). Je n’ai pas pu afficher le curseur occupé uniquement sur un conteneur particulier du formulaire (mais je n’ai pas essayé très fort). Tous les contrôles ont une propriété UseWaitCursor, mais cela ne semble pas avoir d’effet sur les contrôles J’ai essayé (peut-être parce qu’ils n’étaient pas au top?)

Voici le journal principal, qui montre les choses qui se passent dans l’ordre que nous attendons:

 16:51:33.1064 Launching lengthy operation... 16:51:33.1215 Task Start 16:51:33.1215 Before Await 16:51:33.1215 ...Lengthy operation launched. 16:51:49.1276 After await 16:51:49.1537 Finally 

Okey, le sharepoint vue des autres est très clair, mais j’aimerais faire quelques ajouts, comme suit:

 Cursor tempCursor = Cursor.Current; Cursor.Current = Cursors.WaitCursor; //do Time-consuming Operations Cursor.Current = tempCursor; 

Avec la classe ci-dessous, vous pouvez faire la suggestion de Donut “exception sûre”.

 using (new CursorHandler()) { // Execute your time-intensive hashing code here... } 

la classe CursorHandler

 public class CursorHandler : IDisposable { public CursorHandler(Cursor cursor = null) { _saved = Cursor.Current; Cursor.Current = cursor ?? Cursors.WaitCursor; } public void Dispose() { if (_saved != null) { Cursor.Current = _saved; _saved = null; } } private Cursor _saved; } 

Utilisez ceci avec WPF:

 Cursor = Cursors.Wait; // Your Heavy work here Cursor = Cursors.Arrow;