Как асинхронно ждать X секунд и выполнить что-то?
Я знаю, что есть Thread.Sleep
и System.Windows.Forms.Timer
и Monitor.Wait
в C# и Windows Forms. Я просто не могу понять, как ждать X секунд, а затем делать что - то еще-без блокировки потока.
у меня есть форма с кнопкой. При нажатии кнопки таймер запускается и ждет 5 секунд. После этих 5 секунд какой-то другой элемент управления на форме окрашивается в зеленый цвет. При использовании Thread.Sleep
, все приложение станет невосприимчивым для 5 секунды-так как же мне просто "сделать что-то после 5 секунд"?
7 ответов
(расшифровано от Бена как комментарий)
просто используйте систему.Окна.Формы.Таймер. Установите таймер на 5 секунд и обработайте событие Tick. Когда событие вспыхнет, сделайте это.
...и отключите таймер (IsEnabled=false), прежде чем выполнять свою работу в oder, чтобы подавить секунду.
галочку событие мая выполняется в другом потоке, который не может изменить ваш gui, вы можете поймать это:
private System.Windows.Forms.Timer myTimer = new System.Windows.Forms.Timer();
private void StartAsyncTimedWork()
{
myTimer.Interval = 5000;
myTimer.Tick += new EventHandler(myTimer_Tick);
myTimer.Start();
}
private void myTimer_Tick(object sender, EventArgs e)
{
if (this.InvokeRequired)
{
/* Not on UI thread, reenter there... */
this.BeginInvoke(new EventHandler(myTimer_Tick), sender, e);
}
else
{
lock (myTimer)
{
/* only work when this is no reentry while we are already working */
if (this.myTimer.Enabled)
{
this.myTimer.Stop();
this.doMyDelayedWork();
this.myTimer.Start(); /* optionally restart for periodic work */
}
}
}
}
просто для полноты: с async / await можно отложить выполнение чего-то очень простого (один выстрел, никогда не повторяйте вызов):
private async Task delayedWork()
{
await Task.Delay(5000);
this.doMyDelayedWork();
}
//This could be a button click event handler or the like */
private void StartAsyncTimedWork()
{
Task ignoredAwaitableResult = this.delayedWork();
}
дополнительные сведения см. В разделе "async and await" в MSDN.
Вы можете запустить асинхронную задачу, которая выполняет свои действия:
Task.Factory.StartNew(()=>
{
Thread.Sleep(5000);
form.Invoke(new Action(()=>DoSomething()));
});
[EDIT]
чтобы пройти интервал, вам просто нужно сохранить его в переменной:
int interval = 5000;
Task.Factory.StartNew(()=>
{
Thread.Sleep(interval);
form.Invoke(new Action(()=>DoSomething()));
});
[/EDIT]
вы смотрите на это неправильно. Нажмите кнопку, она запускает таймер с интервалом в x секунд. Когда они вверх, это eventhandler выполняет задачу.
Так что вы не хотите, чтобы произошло.
в то время как X секунд истекают.?
во время выполнения задачи?
Если, например, вы не хотите, чтобы кнопка была нажата до тех пор, пока задержка и задача не будут выполнены. Отключите его в обработчике нажатия кнопки и включите его в задаче завершение.
Если все, что вам нужно, это задержка на пять секунд до задачи, то вы должны передать задержку запуска задаче и позволить ей позаботиться об этом.
ваше приложение зависает, потому что вы вызываете 5-секундный сон/ожидание в основном потоке пользовательского интерфейса. поместите действие sleep/wait / whatever в отдельный поток (на самом деле система.Окна.Формы.Таймер должен сделать это за вас), и когда он завершится, вызовите действие, которое превратит некоторый контроль в зеленый. не забудьте проверить InvokeRequired. вот короткий пример (SetText может быть вызван из другого потока, если это вызов, вместо этого будет вызван в основном потоке пользовательского интерфейса, где находится текстовое поле on):
private void SetText(string text)
{
// InvokeRequired required compares the thread ID of the
// calling thread to the thread ID of the creating thread.
// If these threads are different, it returns true.
if (this.textBox1.InvokeRequired)
{
SetTextCallback d = new SetTextCallback(SetText);
this.Invoke(d, new object[] { text });
}
else
{
this.textBox1.Text = text;
}
}
Я взял образец от здесь (стоит прочитать!).
@eFloh в сообщении, помеченном как ответ, сказал:
событие Tick может быть выполнено в другом потоке, который не может изменить ваш GUI, вы можете поймать это ...
Это не то, что говорят врачи.
Вы используете систему.Окна.Формы.Таймер в примере кода.
Это формы.Таймер.
Согласно документам C# события таймера вызываются в потоке пользовательского интерфейса.
Этот Windows таймер предназначен для однопоточной среде, где Потоки пользовательского интерфейса используются для выполнения обработки. Это требует, чтобы пользователь код имеет доступный насос сообщений UI и всегда работает от одного и того же нитка...
см. Также сообщение stackoverflow здесь
Я думаю, что вы ищете System.Timers
... Я не думаю, что вам нужно установить таймер CWND для того, что вы пытаетесь сделать: посмотрите наhttp://msdn.microsoft.com/en-us/library/0tcs6ww8 (v=VS.90).aspx Для примера. Это должно сработать.
ты пробовал
public static Task Delay(
int millisecondsDelay
)
Вы можете использовать такой:
await Task.Deplay(5000);
ссылка:https://msdn.microsoft.com/en-us/library/hh194873 (v=против 110).aspx