c# - C#中的毫秒级精确定时器

标签 c# wpf timer

我正在使用计时器类(System.Timers.Timer 的包装器),我想用它在 WPF 窗口中显示 2 分钟的倒计时,精确到每 10 毫秒。基本上,我想以 mm\\:ss\\.ff 格式显示每 10 毫秒更新一次的字符串。这是我的类(class):

using System;
using System.Timers;
using Proj.Utilities.Extensions;

namespace Proj.Framework
{
/// <summary>
/// Counts down in wall time, raising events at a specified updated period.
/// </summary>
public sealed class MillisecondTimer
{
    private readonly TimeSpan _initialTime;
    private readonly Timer _timerRep;
    private TimeSpan _timeRemaining;

    /// <summary>
    /// The time remaining in the countdown.
    /// </summary>
    public TimeSpan TimeRemaining
    {
        get { return _timeRemaining; }
        private set
        {
            _timeRemaining = value;
            if (_timeRemaining <= TimeSpan.Zero)
            {
                InvokeCountDownElapsed();
            }
        }
    }

    /// <summary>
    /// True if the timer is currently counting down; false otherwise.
    /// </summary>
    public bool IsCountingDown => _timerRep.Enabled;

    /// <summary>
    /// Raised every time the update period elapses.
    /// </summary>
    public event EventHandler TimeChanged;

    /// <summary>
    /// Raised when the entire countdown elapses.
    /// </summary>
    public event EventHandler CountDownElapsed;

    /// <summary>
    /// Creates a new CountDownTimer.
    /// </summary>
    /// <param name="countDownTime">
    /// The amount of time the timer should count down for.
    /// </param>
    /// <param name="updatePeriod">
    /// The period with which the CountDownTimer should raise events.
    /// </param>
    public MillisecondTimer(TimeSpan countDownTime, TimeSpan updatePeriod)
    {
        _initialTime = countDownTime;
        _timerRep = new Timer(10) { AutoReset = true };


        AttachEventHandlers();
    }

    private void AttachEventHandlers()
    {
        AttachedElapsedEventHandler();
        AttachCountDownElapsedEventHandler();
    }

    private void AttachedElapsedEventHandler()
    {
        _timerRep.Elapsed += OnElapsed;
    }

    private void AttachCountDownElapsedEventHandler()
    {
        CountDownElapsed += OnCountDownElapsed;
    }

    private void InvokeTimeChanged()
    {
        //Defined in Proj.Utilities.Extentions
        TimeChanged.InvokeIfInstantiated(this, new EventArgs());
    }

    private void InvokeCountDownElapsed()
    {
        CountDownElapsed.InvokeIfInstantiated(this, new EventArgs());
    }

    private void OnElapsed(object sender, ElapsedEventArgs e)
    {
        TimeRemaining -= TimeSpan.FromMilliseconds(10);
        InvokeTimeChanged();
    }

    private void OnCountDownElapsed(object sender, EventArgs e)
    {
        Stop();
    }

    /// <summary>
    /// Restarts the countdown.
    /// </summary>
    public void Restart()
    {
        TimeRemaining = _initialTime;
        _timerRep.Start();
        InvokeTimeChanged();
    }

    /// <summary>
    /// Stops the countdown.
    /// </summary>
    public void Stop()
    {
        _timerRep.Stop();
    }
}
}

它有效,因为它按照我的预期去做,但最终速度太慢了。当我想让它从 10 秒开始倒计时时,大约需要 15 秒。最终目标是一个类能够以 10 毫秒的分辨率准确地从 2 分钟开始倒计时。为什么这比它应该花费的时间更长,我可以做些什么来让它更好地工作?

最佳答案

不要每次都更改您的TimeRemaining - 保持开始时间并与当前时间比较以获得TimeRemaining:

TimeRemaining = (DateTime.Now - _initialTime);

这样,您从 Timer 得到的任何错误都不会累积,但最终会平分。

关于c# - C#中的毫秒级精确定时器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33351971/

相关文章:

c# - 为什么在字典声明中使用接口(interface)?

c# - ICLRRuntimeInfo 到我的 dll - 可能吗?

c# - 为什么 WPF PasswordBox 有时会变成空白,而其他时候却不会?

c# - 使用 MVVM Light 创建通用用户控件

iOS 每天运行一次代码

c# - 谷歌日历 API V3

c# - 不断收到错误 : redirect_uri_mismatch using youtube api v3

wpf - 使用 Visual Studio 指定应用程序的图标

java - 让图形随着关键事件而移动

c++ - 当为不存在的日期/时间设置 CreateWaitableTimer 时会发生什么?