web-dev-qa-db-fra.com

Affichage du curseur d'attente pendant que le travail de fond est en cours

Lors du démarrage de mon application Windows, je dois appeler un service Web pour récupérer des données par défaut à charger sur mon application. Pendant le chargement du formulaire, j'exécute un arrière-plan pour récupérer ces données. Je veux afficher le curseur d'attente jusqu'à ce que ces données soient récupérées. Comment je ferais ça?

J'ai essayé de définir le curseur d'attente avant d'appeler le fond d'écran. Lorsque je signale une progression de 100, je le remets au curseur par défaut. Le curseur d'attente apparaît mais lorsque je déplace la souris, il disparaît.

Environnement:

  • Windows 7 Pro 64 bits
  • VS2010 C # .NET 4.0
  • Windows Forms

EDIT: Je positionne le curseur comme l'a suggéré Jay Riggs. Cela ne fonctionne que si je ne déplace pas la souris.

* * UPDATE: J'ai créé un clic de bouton qui a les effets suivants: Lorsque je clique sur le bouton et que je déplace la souris, le curseur d'attente apparaît même si je déplace ou non ma souris.

void BtnClick()
{
  Cursor = Cursors.WaitCursor;
  Thread.Sleep(8000);
  Cursor = Cursors.Default;
}

Si je fais ce qui suit: je vois le curseur d'attente et lorsque je déplace la souris, il disparaît à l'intérieur du formulaire. Si je passe à la barre d'état ou à la barre de menus, le curseur d'attente apparaît.

Cursor = Cursors.WaitCursor;
if (!backgroundWorker.IsBusy)
{
  backGroundWorker.RunWorkerAsync();
}

void backGroundWorkerDoWork(object sender, DoWorkEventArgs e)
{
  Thread.Sleep(8000);
}

void backGroundWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
  Cursor = Cursors.Default;
}

Si je fais ce qui suit: Le curseur d'attente apparaît et lorsque je déplace la souris, il apparaît toujours, mais clignote parfois de temps en temps lorsque vous vous déplacez dans les champs de texte. Bien que le curseur se transforme en curseur d'attente, cela ne vous empêche pas de cliquer sur quoi que ce soit.

if (!backgroundWorker.IsBusy)
{
  backGroundWorker.RunWorkerAsync();
}

void backGroundWorkerDoWork(object sender, DoWorkEventArgs e)
{
  UseWaitCursor = true;
  Thread.Sleep(8000);
}

void backGroundWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
  UseWaitCursor = false;
}
16
arc1880

Est-ce que UseWaitCursor fonctionne? (Défini sur true lors de l'appel de RunWorkerAsync () et sur False lorsque l'événement d'achèvement est appelé). Qu'utilisez-vous pour définir le curseur maintenant? 

18
Mark Sowul

N'affichez pas de curseur d'attente pour cela. Utilisez plutôt un contrôle sur votre formulaire pour indiquer que le backgroundworker est en train de faire quelque chose. Le curseur d'attente est un indicateur approprié à utiliser par le thread d'interface utilisateur (puisqu'il indique que l'utilisateur ne peut/ne doit rien toucher), mais il n'est pas approprié pour quelque chose qui se passe en arrière-plan.

11
MusiGenesis

Dans WPF, j'ai effectué cette opération en définissant la propriété Mouse.OverrideCursor sur Cursors.Wait avant de démarrer Backgroundworker, puis en le réinitialisant sur null dans l'événement RunWorkerCompleted. Semble fonctionner assez bien jusqu'à présent.

public void go()
{
    BackgroundWorker thread = new BackgroundWorker();

    thread.DoWork += run;
    thread.RunWorkerCompleted += taskCompleted;
    thread.WorkerReportsProgress = true;

    // Change mouse cursor to busy
    Mouse.OverrideCursor = Cursors.Wait;

    thread.RunWorkerAsync();
}

private void taskCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    // Reset mouse cursor
    Mouse.OverrideCursor = null;
}
6
WildCrustacean

Vous devez utiliser l'événement RunWorkerCompleted de BGW pour remettre votre curseur à la valeur par défaut.

MODIFIER:

Attendez que votre curseur attende en appelant ce code avant de démarrer votre BGW:

this.Cursor = Cursors.WaitCursor;

Réinitialisez votre curseur dans l'événement RunWorkerCompleted de BGW en:

this.Cursor = Cursors.Default;
4
Jay Riggs

Dans les forums MS, le fil de discussion UseWaitCursor ne fonctionne pas mais Cursor = Cursors.WaitCursor ne .. .. - & Cursor.Current vs. this.Cursor

il a été confirmé que l'implémentation de UseWaitCursor par WF manquait une occasion de le faire fonctionner pour afficher un curseur en sablier et la classe HourGlass, qui peut être utilisée avec le bloc "using"

using (new HourGlass()) {
        // Do something that takes time...
        System.Threading.Thread.Sleep(2000);
      }
1
Michael Freidgeim

Voici ce que je fais maintenant, j'espère cette aide.

private void LoadWaitCursor()
{
    this.Dispatcher.Invoke((Action)(() =>
    {
        Mouse.OverrideCursor = Cursors.Wait;
    }));
}
private void LoadDefaultCursor()
{
    this.Dispatcher.Invoke((Action)(() =>
    {
        Mouse.OverrideCursor = null;
    }));
}
0
Hung Doan

Quelque chose d'autre doit être en train de mettre le curseur. Le code ci-dessous définit un curseur d'attente lorsque la minuterie démarre, puis remet le curseur à la valeur précédente après expiration de la minuterie. Cela fonctionne comme prévu: le curseur d'attente reste tout au long de l'intervalle. Bien sûr, déplacer le curseur en dehors de la fiche affichera le curseur quelle que soit la fenêtre sur laquelle se trouve le curseur de la souris, mais la ramener à ma fiche affichera le curseur d'attente.

public partial class MyDialog : Form
{
    private Timer myTimer;
    public MyDialog()
    {
        InitializeComponent();
        myTimer = new Timer();
        myTimer.Tick += new EventHandler(myTimer_Tick);
        myTimer.Interval = 5000;
        myTimer.Enabled = false;
    }

    private Cursor SaveCursor;
    private void button1_Click(object sender, EventArgs e)
    {
        Cursor = Cursors.WaitCursor;
        myTimer.Enabled = true;
    }

    void myTimer_Tick(object sender, EventArgs e)
    {
        Cursor = SaveCursor;
        myTimer.Enabled = false;
    }
}
0
Jim Mischel

Le Microsoft Reference Source nous donne l’implémentation de Control.UseWaitCursor et Control.Cursor . Si vous examinez Control.Cursor, vous verrez que si UseWaitCursor est défini sur True, Control.Cursor renvoie Cursor.WaitCursor quel que soit le curseur défini sur le contrôle. En raison de ce comportement, la valeur renvoyée par Control.Cursor ne peut pas être mise en cache.

// DON'T DO THIS: THIS CODE WILL BREAK IF UseWaitCursor IS SET TO TRUE
// Store the original cursor
Cursor cachedCursor = this.Cursor;

// Set the cursor to a wait cursor.
this.Cursor = Cursors.WaitCursor;

// Perform some task

// Restore the original cursor
this.Cursor = cachedCursor;

Bien que ce qui précède semble suffisamment inoffensif, des problèmes peuvent survenir instantanément si quelqu'un définit Control.UseWaitCursor sur True avant son exécution. Le résultat serait un curseur d'attente bloqué du fait que Control.Cursor renvoie Cursors.WaitCursor sur la première ligne de la ligne ci-dessus. Une meilleure méthode pour changer le curseur est donc:

// Change the cursor as needed
this.Cursor = Cursors.WaitCursor;

// Perform some task

// Restore the default cursor when finished.
this.Cursor = this.DefaultCursor;

Dans la grande majorité des cas, ce qui précède devrait suffire à afficher un curseur d’attente en cas de besoin. Toutefois, si un enfant d'un contrôle modifie également le curseur, le curseur défini par l'enfant remplacera celui qui est défini sur le parent. IE si vous définissez le curseur d'une étiquette sur Cursors.IBeam sur un formulaire dont le curseur est sur Cursors.WaitCursor, l'étiquette affichera un IBeam pendant que le formulaire affiche le WaitCursor. Seuls les contrôles pour lesquels Control.Cursor renvoie la même valeur que Control.DefaultCursor afficheront le WaitCursor défini sur le formulaire dans ce cas. C'est là qu'intervient Control.UseWaitCursor. Définir UseWaitCursor sur un formulaire définit également UseWaitCursor sur tous ses enfants. Tant qu'aucun des contrôles du formulaire n'utilise le code cassé ci-dessus. Le DataGridView n'est qu'un des nombreux contrôles utilisant le code cassé ci-dessus.

Mais que se passe-t-il si vous ne voulez pas de WaitCursor et que vous souhaitez conserver le curseur défini en externe par un utilisateur de votre contrôle? Dans ce cas, vos options étant limitées, vous devez remplacer la propriété Cursor de votre contrôle pour recevoir le curseur défini par un utilisateur de votre contrôle OR. Vous devez utiliser la réflexion pour accéder à la valeur du curseur interne stockée par la base. Classe de contrôle. Ensuite, et seulement alors, vous pourrez utiliser la première méthode ci-dessus pour la mise en cache et la restauration du curseur. * Remarque: vous devez mettre en cache la valeur du curseur interne définie par l'utilisateur de votre commande, et non le résultat de base.Cursor!

0
deAtog

Il y a beaucoup de réponses ici déjà mais j'ai trouvé une autre solution qui a fonctionné pour moi alors j'avais pensé la lister.

private void ShowWaitCursor(){
    Application.UseWaitCursor = true; //keeps waitcursor even when the thread ends.
    System.Windows.Forms.Cursor.Current = Cursors.WaitCursor; //Normal mode of setting waitcursor
}

private void ShowNormalCursor(){
    Application.UseWaitCursor = false;
    System.Windows.Forms.Cursor.Current = Cursors.Default;
}

J'utilise les deux en ligne comme ça et ça a l'air de fonctionner comme je m'y attendais tout le temps. Surtout quand je veux avoir un curseur d'attente affiché pendant qu'un travailleur est en cours d'exécution. J'espère que cela aide tous ceux qui cherchent encore.

0
Troublesum