我想用C#做一个简单的Countdown-Application作为例子。
对于第一个和最基本的版本,我使用Label来显示以秒为单位的当前时间和一个用于开始倒计时的Button。 Button的Click-Event实现如下:
private void ButtonStart_Click(object sender, RoutedEventArgs e)
{
_time = 60;
while (_time > 0)
{
_time--;
this.labelTime.Content = _time + "s";
System.Threading.Thread.Sleep(1000);
}
}
现在,当用户点击按钮时,实际倒计时(因为应用程序冻结(由于Sleep())所选的时间量,但Label的上下文未刷新。
我做错了什么(当涉及到线程时)或者它只是UI的一个问题?
感谢您的回答! 我现在使用System.Windows.Threading.DispatcherTimer来做你告诉我的事情。一切正常,所以这个问题得到正式回答;)
对于那些感兴趣的人:这是我的代码(基本部分)
public partial class WindowCountdown : Window
{
private int _time;
private DispatcherTimer _countdownTimer;
public WindowCountdown()
{
InitializeComponent();
_countdownTimer = new DispatcherTimer();
_countdownTimer.Interval = new TimeSpan(0,0,1);
_countdownTimer.Tick += new EventHandler(CountdownTimerStep);
}
private void ButtonStart_Click(object sender, RoutedEventArgs e)
{
_time = 10;
_countdownTimer.Start();
}
private void CountdownTimerStep(object sender, EventArgs e)
{
if (_time > 0)
{
_time--;
this.labelTime.Content = _time + "s";
}
else
_countdownTimer.Stop();
}
}
答案 0 :(得分:10)
是的,事件处理程序不应该阻止 - 它们应该立即返回。 您应该通过Timer,BackgroundWorker或Thread(按此优先顺序)实现它。
答案 1 :(得分:9)
您所看到的是阻止Windows消息队列/泵的长时间运行消息的影响 - 您通常将其与白色应用程序屏幕关联并且“无响应”。基本上,如果你的线程处于休眠状态,它就不会响应像“自己画画”这样的消息。您需要对泵进行更改并控制。
有多种方法可以做到这一点(ripper234可以很好地列出它们)。您经常会看到的糟糕方式是:
{ // your count/sleep loop
// bad code - don't do this:
Application.DoEvents();
System.Threading.Thread.Sleep(1000);
}
我提到仅来强调不要做的事情;这导致了很多“重入”和一般代码管理的问题。更好的方法是使用Timer
或更复杂的代码BackgroundWorker
。类似的东西:
using System;
using System.Windows.Forms;
class MyForm : Form {
[STAThread]
static void Main() {
Application.EnableVisualStyles();
Application.Run(new MyForm());
}
Timer timer;
MyForm() {
timer = new Timer();
count = 10;
timer.Interval = 1000;
timer.Tick += timer_Tick;
timer.Start();
}
protected override void Dispose(bool disposing) {
if (disposing) {
timer.Dispose();
}
base.Dispose(disposing);
}
int count;
void timer_Tick(object sender, EventArgs e) {
Text = "Wait for " + count + " seconds...";
count--;
if (count == 0)
{
timer.Stop();
}
}
}