我想创建一个从计时器获得的 0 到 1 值。该值将描述距离下一个刻度线还有多长时间。0 是距离滴答声最远(以毫秒为单位) 0.5 是滴答声的一半,1 是滴答声的时间。
我怎样才能做到这一点?
一个简单的选择是使用Stopwatch
. 当您启动计时器时启动它,并Restart
在每个滴答处理程序开始时调用 - 实际上,您可以通过添加一个处理程序来单独执行此操作,以便在添加“真实”处理程序之前执行秒表重新启动。
然后你会使用:
double progress = stopwatch.Elapsed.TotalMilliseconds / timer.Interval;
请记住,有时可能会超过 1,因为计时器可能会延迟触发,具体取决于 UI 线程正在执行的其他操作。请注意,这提供了 adouble
而不是 a decimal
,但我认为这更适合这种情况。
您如何封装这实际上取决于您尝试做什么以及您的程序的其余部分如何挂在一起......目前我们没有足够的信息来指导您。
这样的事情会起作用,但是考虑到发生计时器回调时所涉及的抖动量,您最多只能得到一个近似值:
class MyResourceIntensiveTimer : IDisposable
{
private Stopwatch Stopwatch ;
private Timer Timer ;
private long PrevTick ;
private long PeriodInTicks ;
public Decimal TicksToNextTock
{
get
{
long elapsedTicks = Stopwatch.ElapsedTicks - PrevTick ;
decimal value = ((decimal)elapsedTicks) / ((decimal)this.PeriodInTicks) ;
return value ;
}
}
public MyResourceIntensiveTimer( TimeSpan period )
{
if ( period <= TimeSpan.Zero ) throw new ArgumentOutOfRangeException("period") ;
this.PeriodInTicks = period.Ticks ;
this.Timer = new Timer( TimerCallback , null , period , period ) ;
this.PrevTick = (this.Stopwatch=Stopwatch.StartNew()).ElapsedTicks ;
return ;
}
private void TimerCallback( object o )
{
this.PrevTick = Stopwatch.ElapsedTicks ;
this.OnTock.Invoke() ;
return ;
}
public event Action OnTock ;
public void Dispose()
{
if ( this.Stopwatch != null )
{
if ( this.Stopwatch.IsRunning )
{
this.Stopwatch.Stop() ;
}
this.Stopwatch = null ;
}
if ( this.Timer != null )
{
this.Timer.Change(Timeout.Infinite , Timeout.Infinite ) ; // shut things down
this.Timer = null ;
}
}
}