我目前正在编写一个WPF应用程序,我希望它有一个倒数计时器。这是我的CountDown类:
internal class CountDown : INotifyPropertyChanged
{
private readonly DispatcherTimer _timer;
private string _currentTimeString;
private TimeSpan _runTime;
private TimeSpan _timeleft;
public CountDown(TimeSpan runTime)
{
if (runTime == null) throw new ArgumentNullException("runTime");
_runTime = runTime;
_timer = new DispatcherTimer();
_timer.Interval = new TimeSpan(0, 0, 0, 0, 10);
_timer.Tick += Update;
}
public CountDown(TimeSpan runTime, TimeSpan interval)
{
if (runTime == null) throw new ArgumentNullException("runTime");
_runTime = runTime;
_timer = new DispatcherTimer();
if (interval == null) throw new ArgumentNullException("interval");
_timer.Interval = interval;
_timer.Tick += Update;
}
public event PropertyChangedEventHandler PropertyChanged;
public string CurrentTimeString
{
get { return _currentTimeString; }
private set
{
_currentTimeString = value;
NotifyPropertyChanged();
}
}
public void Start()
{
var task = new Task(_timer.Start);
_timeleft = _runTime;
task.Start();
}
private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
private void Update(object sender, EventArgs e)
{
_timeleft -= _timer.Interval;
DateTime newTime = new DateTime();
newTime = DateTime.MinValue;
newTime += _timeleft;
CurrentTimeString = newTime.ToString("mm:ss:ff");
}
}
作文根:
public MainWindow()
{
CountDown countDown = new CountDown(new TimeSpan(0, 1, 0));
InitializeComponent();
tb1.DataContext = countDown; //tb1 = TextBlock
countDown.Start();
}
除非我将间隔设置为10毫秒,然后它比实际秒数慢,否则一切正常。我该如何解决这个问题?
编辑:我还不能回答我自己的问题,所以在这里: 我没有使用任何计时器完全重写了我的课程。发现这些对我来说不够准确。public class CountDown : INotifyPropertyChanged
{
private string _currentTimeString;
private TimeSpan _runTime;
private bool _shouldStop;
private DateTime _timeToStop;
private TimeSpan _updateInterval;
public CountDown(TimeSpan runTime)
{
if (runTime == null) throw new ArgumentNullException("runTime");
_runTime = runTime;
_updateInterval = new TimeSpan(0, 0, 0, 0, 10);
Tick += Update;
}
public CountDown(TimeSpan runTime, TimeSpan updateInterval)
{
if (runTime == null) throw new ArgumentNullException("runTime");
_runTime = runTime;
if (updateInterval == null) throw new ArgumentNullException("updateInterval");
_updateInterval = updateInterval;
Tick += Update;
}
public event PropertyChangedEventHandler PropertyChanged;
public event Action Tick;
public string CurrentTimeString
{
get { return _currentTimeString; }
set
{
_currentTimeString = value;
NotifyPropertyChanged();
}
}
public void Start()
{
_shouldStop = false;
_timeToStop = DateTime.Now + _runTime;
var task = new Task(GenerateTicks);
task.Start();
}
public void Stop()
{
_shouldStop = true;
}
private void GenerateTicks()
{
while (_shouldStop == false)
{
if (Tick != null)
Tick();
Thread.Sleep(_updateInterval);
}
}
private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
private void Update()
{
var timeLeft = _timeToStop - DateTime.Now;
if (timeLeft <= TimeSpan.Zero)
{
_shouldStop = true;
return;
}
var timeLeftDate = DateTime.MinValue + timeLeft;
CurrentTimeString = timeLeftDate.ToString("mm:ss:ff");
}
}
答案 0 :(得分:1)
首先,您不需要任务来完成倒计时。如果你使用一个每隔50ms滴答一次的计时器,你就不会阻止任何事情。比50分钟更快的嘀嗒声更有意义,因为我猜你的倒计时显示小时,分钟或秒。毫秒对于计时器来说有点太多了,不是吗?即使您想要显示ms范围,人眼也不会注意倒计时是每10或50毫秒更新一次。
接下来,如果您使用DateTime作为时基,则可能更容易处理。它可以更容易地计算实际剩余时间。
using System;
using System.Timers;
public class Countdown
{
private readonly TimeSpan countdownTime;
private readonly Timer timer;
private DateTime startTime;
public Countdown(TimeSpan countdownTime)
{
this.countdownTime = countdownTime;
this.timer = new Timer(10);
}
public string RemainingTime { get; private set; }
public void Start()
{
this.startTime = DateTime.Now;
this.timer.Start();
}
private void Timer_Tick(object state)
{
var now = DateTime.Now;
var difference = now - this.startTime;
var remaining = this.countdownTime - difference;
if (remaining < TimeSpan.Zero)
{
this.timer.Stop();
// Raise Event or something
}
this.RemainingTime = remaining.ToString("mm:ss:fff");
}
}
对于这种情况,异步倒计时会有点过分。但如果你需要它,它很容易升级。
答案 1 :(得分:0)
您的Countdown类在构造函数中有2个参数。在这种情况下,你没有调用你的单个参数构造函数(你有10ms的那个)。您在第二个参数中为间隔提供1s(新TimeSpan(0,0,1)),这是您在运行时在UI中看到的内容。