Thread.Sleep (300) работает неправильно - PullRequest
1 голос
/ 22 декабря 2010

Я хочу, чтобы он выполнил первую часть кода, затем сделал видимым pictureBox, сделал паузу на 3 секунды, скрыл pictureBox и выполнил остальную часть кода:

// first part of the code here
pb_elvisSherlock.Visible = true;
Thread.Sleep(300);
pb_elvisSherlock.Visible = false;
// rest of the code here

Но он выполняет весь блок кода и только потом останавливается. Есть идеи что делать?

Спасибо!

Ответы [ 7 ]

11 голосов
/ 22 декабря 2010

Если вы пытаетесь заставить PictureBox появляться в течение 3 секунд, вы, вероятно, хотите, чтобы ваше приложение оставалось отзывчивым в течение этого времени.Поэтому использование Thread.Sleep не является хорошей идеей, поскольку ваш поток графического интерфейса не обрабатывает сообщения во время сна.

Лучшей альтернативой будет установка System.Windows.Forms.Timer на 3000 мс, чтобы скрыть PictureBox после 3секунд без блокировки вашего графического интерфейса.

Например, вот так:

pb.Visible = true;
var timer = new Timer();
timer.Tick += () => { pb.Visible = false; timer.Stop(); };
timer.Interval = 3000;
timer.Start();
5 голосов
/ 22 декабря 2010
pb_elvisSherlock.Visible = true;
Application.DoEvents(); //let the app show the picturebox
Thread.Sleep(3000);
pb_elvisSherlock.Visible = false;

Проблема в том, что вы не даете циклу сообщений возможность отобразить графическое окно, прежде чем вы приостановите поток графического интерфейса. Application.DoEvents() решите это.

Обратите внимание, что использование Thread.Sleep в потоке графического интерфейса приведет к зависанию рисунка (попробуйте переместить окно поверх вашего приложения, когда Sleep активен).

Вы должны сделать что-то вроде этого:

pb_elvisSherlock.Visible = true;
int counter = 0;
while (counter < 30)
{
  Application.DoEvents(); 
  Thread.Sleep(100);
  ++counter;
}
pb_elvisSherlock.Visible = false;

Это все еще своего рода хак, но окно будет перерисовано и ответит как следует.

Обновление 2

Хорошо. DoEvents похоже, что-то вроде хака. (спасибо за комментарии).

Если картинка-бокс представляет собой нечто вроде придирчивого экрана, сделайте что-то вроде этого:

Альтернатива 1

  1. Создайте новую форму, содержащую только поле рисунка (не используйте границы для этой формы).
  2. Добавьте к этой форме таймер, который через три секунды вызывает Close
  3. вызов 'myNagForm.DoModal ()'

Это решение препятствует тому, чтобы ваши пользователи делали что-либо в вашей "нормальной" форме, пока nagform видна.

Альтернатива 2

  1. Создание фонового работника, см. Здесь, например: http://dotnetperls.com/backgroundworker
  2. Переместите изображение и код, выполненный после него, в метод фонового рабочего.
3 голосов
/ 22 декабря 2010

Проблема в том, что вы блокируете поток пользовательского интерфейса, который отвечает за перерисовку вашей формы, поэтому ничего не перерисовывается в течение 3 секунд, которые вы ждете (попробуйте перетащить форму в течение этих 3 секунд, и вы увидим, это совершенно не отвечает).

Существует множество способов справиться с этим, но основная предпосылка заключается в том, что сначала вам нужно подождать в фоновом потоке, чтобы ваш поток пользовательского интерфейса оставался отзывчивым (варианты включают использование BackgroundWorker , Таймер , ThreadPool , Thread или TPL TaskFactory ). Во-вторых, вы должны помнить, что любое обновление пользовательского интерфейса должно выполняться в потоке пользовательского интерфейса, поэтому вы должны переключиться обратно в свой поток пользовательского интерфейса (используя .Invoke () или TaskScheduler ). перед тем как скрыть графическое окно в конце.

В этом примере используется TPL (библиотека параллельных задач):

// Start by making it visible, this can be done on the UI thread.
pb_elvisSherlock.Visible = true;

// Now grab the task scheduler from the UI thread.
var uiScheduler = TaskScheduler.FromCurrentSynchronizationContext();

// Now create a task that runs on a background thread to wait for 3 seconds.
Task.Factory.StartNew(() =>
{
    Thread.Sleep(3000);

// Then, when this task is completed, we continue...
}).ContinueWith((t) =>
{
    //... and hide your picture box.
    pb_elvisSherlock.Visible = false;

// By passing in the UI scheduler we got at the beginning, this hiding is done back on the UI thread.
}, uiScheduler);
1 голос
/ 22 декабря 2010

Во-первых, вы спите только 300 миллисекунд, а не 3 секунды

Thread.Sleep(3000);

Во-вторых, ваш пользовательский интерфейс сначала обновится, когда ваш код будет выполнен, поэтому вам нужно выполнить что-то вроде это

1 голос
/ 22 декабря 2010

Я бы попробовал сделать это дольше:

Thread.Sleep(300);

изменить на

Thread.Sleep(3000);

Вы останавливаетесь только на 0,3 секунды в вашем примере (3000 = 3 секунды). Если бы я должен был догадаться, вы не ждете достаточно долго для отображения окна. Код на самом деле работает правильно.

Как и комментарий, попробуйте добавить Application.DoEvents(); после установки свойства видимости.

0 голосов
/ 05 февраля 2019

Вы можете попробовать это Task.Delay(TimeSpan.FromSeconds(3)).Wait(); везде, где метод Thread.Sleep иногда не блокирует поток.

0 голосов
/ 22 декабря 2010

Расширения весьма полезны в таких ситуациях; -)

public static class IntExtensions
{
    public static TimeSpan Seconds(this int value)
    {
        return new TimeSpan(0, 0, value);
    }
}

Thread.Sleep(3.Seconds());
...