我目前正在编写一个 WPF 应用程序,我想在其中包含一个倒数计时器。这是我的倒计时课:
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");
}
}