简体   繁体   English

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

[英]C# Simple Countdown - What am I doing wrong?

I wanted to make a simple Countdown-Application with C# to show as an example. 我想用C#做一个简单的Countdown-Application作为例子。

For the very first and basic version I use a Label to display the current time left in seconds and a Button to start the countdown. 对于第一个和最基本的版本,我使用Label来显示剩余的当前时间(以秒为单位)和一个Button来开始倒计时。 The Button's Click-Event is implemented like this: 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);
        }
    }

Now when the user clicks the Button the time is actually counted down (as the application freezes (due to Sleep())) for the chosen amount of time but the Label's context is not refreshed. 现在,当用户单击按钮时,实际倒计时(因为应用程序冻结(由于Sleep())所选的时间量,但Label的上下文未刷新。

Am I doing something generally wrong (when it comes to Threads) or is it just a problem with the UI? 我做的事情一般是错的(当谈到线程时)或者它只是UI的一个问题?


Thank you for your answers! 谢谢您的回答! I now use a System.Windows.Threading.DispatcherTimer to do as you told me. 我现在使用System.Windows.Threading.DispatcherTimer来做你告诉我的事情。 Everything works fine so this question is officially answered ;) 一切正常,所以这个问题得到正式回答;)

For those who are interested: Here is my code (the essential parts) 对于那些感兴趣的人:这是我的代码(基本部分)

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

Yes, event handlers should not block - they should return immediately. 是的,事件处理程序不应该阻止 - 它们应该立即返回。 You should implement this by a Timer, BackgroundWorker or Thread (in this order of preference). 您应该通过Timer,BackgroundWorker或Thread(按此优先顺序)实现此功能。

What you are seeing is the effect of a long-running message blocking the windows message queue/pump - which you more commonly associate with the white application screen and "not responding". 您所看到的是阻止Windows消息队列/泵的长时间运行消息的影响 - 您通常将其与白色应用程序屏幕关联并且“无响应”。 Basically, if your thread is sleeping, it isn't responding to messages like "paint yourself". 基本上,如果你的线程处于休眠状态,它就不会响应像“自己画画”这样的消息。 You need to make your change and yield control to the pump. 您需要对泵进行更改并控制

There are various ways of doing this (ripper234 does a good job of listing them). 有多种方法可以做到这一点(ripper234可以很好地列出它们)。 The bad way you'll often see is: 你经常看到的方法是:

{ // your count/sleep loop

    // bad code - don't do this:
    Application.DoEvents();
    System.Threading.Thread.Sleep(1000);
}

I mention this only to highlight what not to do; 我提到这一点只是为了强调不该做的事; this causes a lot of problems with "re-entrancy" and general code management. 这导致了很多“重入”和一般代码管理的问题。 A better way is simply to use a Timer , or for more complex code, a BackgroundWorker . 更好的方法是使用Timer或更复杂的代码,使用BackgroundWorker Something like: 就像是:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM