web-dev-qa-db-fra.com

Attendez quelques secondes sans bloquer l'exécution de l'interface utilisateur

Je voudrais attendre quelques secondes entre deux instructions, mais SANS bloquer l'exécution.

Par exemple, Thread.Sleep(2000) n'est pas bon, car il bloque l'exécution.

L'idée est que j'appelle une méthode puis j'attends X secondes (20 par exemple) à l'écoute d'un événement à venir. À la fin des 20 secondes, je devrais effectuer une opération en fonction de ce qui s'est passé dans les 20 secondes.

51
user3376691

Je pense que ce que vous cherchez, c'est Task.Delay. Cela ne bloque pas le thread comme le fait le sommeil et cela signifie que vous pouvez le faire en utilisant un seul thread en utilisant le modèle de programmation async.

async Task PutTaskDelay()
{
    await Task.Delay(5000);
} 

private async void btnTaskDelay_Click(object sender, EventArgs e)
{
    await PutTaskDelay();
    MessageBox.Show("I am back");
}
81
daniellepelley

J'utilise:

private void WaitNSeconds(int segundos)
{
    if (segundos < 1) return;
    DateTime _desired = DateTime.Now.AddSeconds(segundos);
    while (DateTime.Now < _desired) {
         System.Windows.Forms.Application.DoEvents();
    }
}
23
Omar

C'est un bon cas pour utiliser un autre thread:

// Call some method
this.Method();

Task.Factory.StartNew(() =>
{
    Thread.Sleep(20000);

    // Do things here.
    // NOTE: You may need to invoke this to your main thread depending on what you're doing
});

Le code ci-dessus attend .NET 4.0 ou supérieur, sinon essayez:

ThreadPool.QueueUserWorkItem(new WaitCallback(delegate
{
    Thread.Sleep(20000);

    // Do things here
}));
12
Matt

La solution d'Omar est décente * si vous ne pouvez pas mettre à niveau votre environnement vers .NET 4.5 pour pouvoir accéder à async et attendre des API. Cela dit, un changement important doit être apporté pour éviter de mauvaises performances. Un léger délai doit être ajouté entre les appels à Application.DoEvents () afin d'éviter une utilisation excessive du processeur. En ajoutant

Thread.Sleep(1);

avant l'appel à Application.DoEvents (), vous pouvez ajouter un tel délai (1 milliseconde) et empêcher l'application d'utiliser tous les cycles cpu disponibles.

private void WaitNSeconds(int seconds)
{
    if (seconds < 1) return;
    DateTime _desired = DateTime.Now.AddSeconds(seconds);
    while (DateTime.Now < _desired) {
         Thread.Sleep(1);
         System.Windows.Forms.Application.DoEvents();
    }
}

* Voir https://blog.codinghorror.com/is-doevents-evil/ pour une discussion plus détaillée sur les pièges potentiels de l'utilisation de Application.DoEvents ().

10
Nick Painter

Si vous ne souhaitez pas bloquer des éléments et ne pas utiliser plusieurs threads, voici la solution: https://msdn.Microsoft.com/en-us/library/system.timers.timer ( v = vs.110) .aspx

Le thread d'interface utilisateur n'est pas bloqué et la minuterie attend 2 secondes avant de faire quelque chose.

Voici le code provenant du lien ci-dessus:

        // Create a timer with a two second interval.
    aTimer = new System.Timers.Timer(2000);
    // Hook up the Elapsed event for the timer. 
    aTimer.Elapsed += OnTimedEvent;
    aTimer.Enabled = true;

    Console.WriteLine("Press the Enter key to exit the program... ");
    Console.ReadLine();
    Console.WriteLine("Terminating the application...");
3
Daan

je vous déconseille vraiment d'utiliser Thread.Sleep(2000), pour plusieurs raisons (quelques-unes sont décrites ici ), mais surtout parce que ce n'est pas utile pour le débogage/test.

Je recommande d'utiliser un minuteur C # au lieu de Thread.Sleep(). Les minuteries vous permettent d'effectuer des méthodes fréquemment (si nécessaire) ET sont beaucoup plus faciles à utiliser lors des tests! Il existe un très bel exemple d'utilisation d'un timer juste derrière le lien hypertexte - il suffit de mettre votre logique "que se passe-t-il après 2 secondes" directement dans la méthode Timer.Elapsed += new ElapsedEventHandler(OnTimedEvent);.

2
Matthias R.

Regardez dans System.Threading.Timer classe. Je pense que c'est ce que vous recherchez.

Le exemple de code sur MSDN semble montrer que cette classe est très similaire à ce que vous essayez de faire (vérifier le statut après un certain temps).

0
LB2