2014-12-06 152 views
0

我用下面的代码:如何使用C#停止计时器计数器为零?

DispatcherTimer sec = new DispatcherTimer(); 
sec.Interval = new TimeSpan(0, 0, 0, 1); 

sec.Tick += delegate 
{ 
    lblsec.Text = b--.ToString() + " Seconds."; 
}; 

sec.Start(); 
c--; 

该代码会显示从5计数器开始,并会降低下来,它会变为负。 我的问题是当它达到零时如何阻止它?

+0

您在'Tick'称为'sec.Stop':例如,你可以使它看起来像这样,而不是改变StartCommand.Execute()方法。这是否会触发不止一次? – 2014-12-06 15:17:36

+0

你确实。但我希望它从5开始并停在零。 – GLviz 2014-12-06 15:26:48

+0

'if(b> 0)b - ;'? – 2014-12-06 15:34:26

回答

1

首先,您的计时器间隔太短。你永远不会从Windows获得单毫秒定时器间隔,而且出于UI的目的,用户永远不会很快察觉到定时器更新。对于这样的事情,100ms或更长时间更合适。

其次,你不能指望计时器是非常精确的。例如,如果您指定100毫秒的时间间隔,则您可能会在一秒钟内回拨十次,但通常您不会。它将取决于Windows线程调度程序的解析以及UI线程正在执行的其他活动。

考虑到这一点,并与你正试图在这里做的是设置一个五秒钟的定时器,显示倒计时到用户的假设,这样的事情应该工作:

TimeSpan total = TimeSpan.FromSeconds(5); 
DispatcherTimer timer = new DispatcherTimer(); 
Stopwatch sw = new Stopwatch(); 

timer.Interval = TimeSpan.FromMilliseconds(100); 
timer.Tick += (sender, e) => 
{ 
    double secondsLeft = (total - sw.Elapsed).TotalSeconds; 

    if (secondsLeft <= 0) 
    { 
     timer.Stop(); 
     secondsLeft = 0; 
    } 

    lblsec.Text = secondsLeft.ToString("0.0") + " Seconds"; 
}; 

sw.Start(); 
timer.Start(); 


附录:

这里是示出了如何在上面的代码可以用于一个完整的WPF程序:

C# :

class TimerModel : INotifyPropertyChanged 
{ 
    private TimeSpan _timeLeft; 
    private readonly ICommand _startCommand; 

    public TimeSpan TimeLeft 
    { 
     get { return _timeLeft; } 
     set 
     { 
      if (value != _timeLeft) 
      { 
       _timeLeft = value; 
       OnPropertyChanged(); 
      } 
     } 
    } 

    public ICommand Start { get { return _startCommand; } } 

    public TimerModel() 
    { 
     _startCommand = new StartCommand(this); 
    } 

    private class StartCommand : ICommand 
    { 
     private bool _running; 
     private readonly TimerModel _timerModel; 

     public bool CanExecute(object parameter) 
     { 
      return !_running; 
     } 

     public event EventHandler CanExecuteChanged; 

     public StartCommand(TimerModel timerModel) 
     { 
      _timerModel = timerModel; 
     } 

     public void Execute(object parameter) 
     { 
      TimeSpan total = TimeSpan.FromSeconds(5); 
      DispatcherTimer timer = new DispatcherTimer(); 
      Stopwatch sw = new Stopwatch(); 

      timer.Interval = TimeSpan.FromMilliseconds(100); 
      timer.Tick += (sender, e) => 
      { 
       TimeSpan timeLeft = total - sw.Elapsed; 

       if (timeLeft <= TimeSpan.Zero) 
       { 
        timer.Stop(); 
        timeLeft = TimeSpan.Zero; 
        _running = false; 
        OnCanExecuteChanged(); 
       } 

       _timerModel.TimeLeft = timeLeft; 
      }; 

      sw.Start(); 
      timer.Start(); 
      _running = true; 
      OnCanExecuteChanged(); 
     } 

     private void OnCanExecuteChanged() 
     { 
      EventHandler handler = CanExecuteChanged; 

      if (handler != null) 
      { 
       handler(this, EventArgs.Empty); 
      } 
     } 
    } 

    public event PropertyChangedEventHandler PropertyChanged; 

    private void OnPropertyChanged([CallerMemberName]string propertyName = null) 
    { 
     PropertyChangedEventHandler handler = PropertyChanged; 

     if (handler != null) 
     { 
      handler(this, new PropertyChangedEventArgs(propertyName)); 
     } 
    } 
} 

XAML:

<Window x:Class="TestSO27333077CountdownTimer.MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     xmlns:l="clr-namespace:TestSO27333077CountdownTimer" 
     Title="MainWindow" Height="350" Width="525"> 

    <Window.DataContext> 
    <l:TimerModel/> 
    </Window.DataContext> 

    <StackPanel> 
    <Button Content="Start" Command="{Binding Start}" HorizontalAlignment="Left"/> 
    <TextBlock Text="{Binding TimeLeft.TotalSeconds, StringFormat={}{0:0.0} Seconds}"/> 
    </StackPanel> 
</Window> 

注意,计时也可以使用DateTime.UtcNow属性,而不是一个Stopwatch来完成。

 public void Execute(object parameter) 
     { 
      DateTime finishTime = DateTime.UtcNow + TimeSpan.FromSeconds(5); 
      DispatcherTimer timer = new DispatcherTimer(); 

      timer.Interval = TimeSpan.FromMilliseconds(100); 
      timer.Tick += (sender, e) => 
      { 
       TimeSpan timeLeft = finishTime - DateTime.UtcNow; 

       if (timeLeft <= TimeSpan.Zero) 
       { 
        timer.Stop(); 
        timeLeft = TimeSpan.Zero; 
        _running = false; 
        OnCanExecuteChanged(); 
       } 

       _timerModel.TimeLeft = timeLeft; 
      }; 

      timer.Start(); 
      _running = true; 
      OnCanExecuteChanged(); 
     } 
+0

是否需要在timer1_Tick()事件中添加此代码? – John 2016-02-07 09:30:37

+1

@John:不,我显示的代码会添加到任何你想启动定时器的地方。不需要'timer1_Tick()'事件处理程序方法,因为代码示例本身已经具有该事件处理程序,并被声明为直接订阅该事件的匿名方法(即'timer.Tick + =(sender,e) => {...};')。我已经添加了一个完整的代码示例以更好地说明如何使用我发布的原始代码。 – 2016-02-07 17:09:47