C#简单倒计时 - 我做错了什么?

时间:2009-06-02 22:21:30

标签: c# wpf multithreading

我想用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();
    }
}

2 个答案:

答案 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();
        }
    }
}