簡體   English   中英

C#中的毫秒精確計時器

[英]Millisecond precise timer in C#

我正在使用一個計時器類( System.Timers.Timer周圍的包裝器),我想用它在WPF窗口中顯示2分鍾的倒計時,精確到每10毫秒。 基本上,我想以mm\\\\:ss\\\\.ff格式顯示一個字符串,每10毫秒更新一次。 這是我的課程:

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分鍾,10毫秒分辨率開始倒數。 為什么這需要的時間超過應有的時間,我能做些什么才能讓它更好用呢?

不要每次都更改TimeRemaining - 保持開始時間並與當前時間進行比較以獲得TimeRemaining

TimeRemaining = (DateTime.Now - _initialTime);

這樣,從Timer獲得的任何錯誤都不會累積,而是最終會均衡。

我曾經寫過一個圍繞多媒體計時器API的包裝器,它可以准確地達到1毫秒,見這里 未經生產用途測試,因此請注意。

但是,您的方法似乎對我不正確。 問問自己是否真的需要准確的10 ms時間來顯示2分鍾間隔的倒計時。 你似乎在計時器上放了兩個責任。 保持准確的時間並定期舉辦活動。 定時器僅適用於這兩者中的后者。 使用Stopwatch准確地保持時間。 使用計時器從秒表獲取經過的時間並定期更新顯示。 這樣,無論計時器的准確性如何,時間都能保持准確。 用戶不會注意到計時器經過多長時間的微小偏差,如果每10或20ms更新一次,則不會關心。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM