Таймер обратного отсчета С#
Я пытаюсь сделать обратный отсчет с помощью С# и показать время в формате:
hour:minutes:seconds
Я пробовал это:
var minutes = 3; //countdown time
var start = DateTime.Now;
var end = DateTime.Now.AddMinutes(minutes);
Thread.Sleep(1800);
if (??) // I tried DateTime.Now > end not works
{
//... show time
label1.Text = "...";
}
else
{
//done
label1.Text = "Done!";
}
Появились и другие способы решения этой проблемы. Спасибо заранее
Ответы
Ответ 1
Здесь вы не должны использовать Thread.Sleep
. Thread.Sleep
в потоке пользовательского интерфейса блокирует пользовательский интерфейс, а его использование в другом потоке приводит к дополнительной сложности из-за синхронизации потоков.
Если у вас есть С# 5 или async CTP, вы, вероятно, можете написать код, очень похожий на то, что вы сделали, поскольку затем вы получаете эквивалент Thread.Sleep
на основе продолжения, который не блокирует пользовательский интерфейс.
В стандартном С# 4 я бы использовал System.Windows.Forms.Timer
.
Чтобы начать обратный отсчет:
var minutes = 3; //countdown time
var start = DateTime.UtcNow; // Use UtcNow instead of Now
endTime = start.AddMinutes(minutes); //endTime is a member, not a local variable
timer1.Enabled = true;
В обработчике таймера вы пишете:
TimeSpan remainingTime=endTime-DateTime.UtcNow;
if(remainingTime<TimeSpan.Zero)
{
label1.Text = "Done!";
timer1.Enabled=false;
}
else
{
label1.Text = remainingTime.ToString();
}
Для других параметров форматирования см. Стандартные строки формата TimeSpan.
Одна проблема, которая остается с этим кодом, заключается в том, что она не будет работать корректно, если системные часы будут изменены.
При использовании DateTime.Now
вместо DateTime.UtcNow
он также ломается при переключении с/на летнее или изменение часового пояса. Поскольку вы хотите определить определенный момент времени (а не время отображения), вы должны использовать UTC вместо локального времени.
Ответ 2
Я бы использовал таймер примерно так. Сначала пара переменных экземпляра.
private int _countDown = 30; // Seconds
private Timer _timer;
и в событии конструктора или загрузки
_timer = new Timer();
_timer.Tick += new EventHandler(timer_Tick);
_timer.Interval = 1000;
_timer.Start();
а затем, наконец, обработчик события
void timer_Tick(object sender, EventArgs e)
{
_countDown--;
if (_countDown < 1)
{
_countDown = 30;
}
lblCountDown.Text = _countDown.ToString();
}
Ответ 3
Вы также можете использовать таймер, так как он будет обрабатывать все проблемы, такие как UI-блокировка.
Вы можете использовать System.Windows.Forms.Timer
-Timer. В библиотеке MSDN вы можете найти образцы его использования.
WinForms-Timer также обрабатывает вызов через поток Timer и UI-поток.
- SeriTools
Ответ 4
Ваш код устанавливает переменные, а затем переходит в спящий режим на 3 минуты, поэтому оператор if не выполняется до тех пор, пока он не покинет состояние ожидания. Либо настройте новый поток для обновления пользовательского интерфейса, либо выполните что-то вроде этого...
while (DateTime.now < end) {
label1.Text = "...";
Thread.Sleep(#); //Pick a second, or 5 or whatever
}
label1.Text = "Done!";
Со вторым потоком вы все равно можете делать что-то в своей программе, пока оно работает. "Готово!" появится после завершения.