2015-09-16 2 views
1

Посмотрите код внизу этого сообщения. Предполагается добавить «3» в список, затем «2» через секунду, затем «1» через секунду, а затем запустить основной код программы. Однако, как только я запускаю программу, он просто остается пустой 3 секунды, после чего отображаются все 3, 2 и 1, после чего начинается весь код. Я хочу визуально видеть, как каждый номер появляется с задержкой в ​​одну секунду. Как мне это сделать?Альтернатива для Thread.Sleep() временно приостановить программу

private void Main() 
     { 
      countdown(); 
      //Main Code 
     } 

private void countdown() 
     { 
      listBox1.Items.Clear(); 
      listBox1.Items.Add("3"); 
      System.Threading.Thread.Sleep(1000); 
      listBox1.Items.Add("2"); 
      System.Threading.Thread.Sleep(1000); 
      listBox1.Items.Add("1"); 
      System.Threading.Thread.Sleep(1000); 
      listBox1.Items.Clear(); 
     } 
+0

Попробуйте искать, Thread.Sleep() блокирует поток пользовательского интерфейса, используйте таймер. – CodeCaster

+3

Включение потока пользовательского интерфейса программы GUI для сна - довольно резкая ошибка с потенциально неприятными последствиями. Не видеть обновления - это всего лишь незначительная ошибка, есть еще хуже. Такие пользователи, как реагирующие программы, не намерены делать это намеренно медленным. Используйте таймер для анимации. –

ответ

8

асинхронного/жду на помощь:

private async void OnButtonClick(object sender, EventArgs e) 
{ 
    listBox1.Items.Clear(); 
    listBox1.Items.Add("3"); 
    await Task.Delay(1000); 

    listBox1.Items.Add("2"); 
    await Task.Delay(1000); 

    listBox1.Items.Add("1"); 
    await Task.Delay(1000); 

    listBox1.Items.Clear(); 
} 
0

Положите listBox1.Refresh(); после каждого Sleep() вызова.

Вы разрешаете потоку спать, но пользовательский интерфейс не перерисовывается автоматически.

5

Первый: Почему ничего не происходит?

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

Второй: Как обойти это?

Как упоминалось в @CodeCaster, вы можете использовать Timer, чтобы сделать все это. Вы также можете поместить свой код в Thread и вызвать метод Add с использованием класса Dispatcher или SynchronizationContext и его метода Send.

В-третьих: Небольшой намек на метод Sleep.

Обычно он должен делать то, что вы ожидаете, но для этого нет никакой гарантии. Вызов Sleep означает, что ваша нить будет приостановлена ​​на примерно количество времени, которое вы хотите. See this answer

1

Редактировать
Использование асинхронной-ОЖИДАНИЕ порекомендован. это более чистые и более гибкие:

private async void countdown() 
{ 
    listBox1.Items.Clear(); 
    listBox1.Items.Add("3"); 
    await Task.Delay(1000); 
    listBox1.Items.Add("2"); 
    await Task.Delay(1000); 
    listBox1.Items.Add("1"); 
    await Task.Delay(1000); 
    listBox1.Items.Clear(); 
} 

Оригинальных

Может быть разными способами, но я проверил это не так красиво код и он работает:

private void countdown() 
{ 
    listBox1.Items.Clear(); 
    Task.Run(() => 
    { 
     listBox1.Invoke(new Action(() => { listBox1.Items.Add("3"); })); 
     System.Threading.Thread.Sleep(1000); 
    }).ContinueWith(x => 
    { 
     listBox1.Invoke(new Action(() => { listBox1.Items.Add("2"); })); 
     System.Threading.Thread.Sleep(1000); 
    }).ContinueWith(x => 
    { 
     listBox1.Invoke(new Action(() => { listBox1.Items.Add("1"); })); 
     System.Threading.Thread.Sleep(1000); 
    }); 
} 
  • Использование ContinueWith является быть последовательным.
  • Использование Invoke связано с тем, что код выполняется в другом потоке, чем поток пользовательского интерфейса.
  • Также вы можете использовать асинхронный-шаблон ждет, чтобы сделать это:

Код:

private async void countdown() 
{ 
    listBox1.Items.Clear(); 
    listBox1.Items.Add("3"); 
    await Task.Delay(1000); 
    listBox1.Items.Add("2"); 
    await Task.Delay(1000); 
    listBox1.Items.Add("1"); 
}