2014-12-06 150 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