如何制作一个wpf倒数计时器?

我想创建wpf倒数计时器,将结果显示为hh:mm:ss到文本框中,我会感谢任何人的帮助。

您可以使用DispatcherTimer类( msdn )。

您可以在TimeSpan结构( msdn )中保留的持续时间。

如果要将TimeSpan格式化为hh:mm:ss ,则应使用“c”参数( msdn )调用ToString方法。

例:

XAML:

      

代码隐藏:

 using System; using System.Windows; using System.Windows.Threading; namespace CountdownTimer { public partial class MainWindow : Window { DispatcherTimer _timer; TimeSpan _time; public MainWindow() { InitializeComponent(); _time = TimeSpan.FromSeconds(10); _timer = new DispatcherTimer(new TimeSpan(0, 0, 1), DispatcherPriority.Normal, delegate { tbTime.Text = _time.ToString("c"); if (_time == TimeSpan.Zero) _timer.Stop(); _time = _time.Add(TimeSpan.FromSeconds(-1)); }, Application.Current.Dispatcher); _timer.Start(); } } } 

为此目的使用DispatcherTimer没有任何问题。 但是,恕我直言,较新的基于TPL的async / await范例使得代码更易于编写和读取。 最好始终为WPF程序使用良好的MVVM实践,而不是直接从代码隐藏设置UI元素值。

这是一个程序的例子,它实现了问题中描述的倒计时器,但使用了这些更现代的实践……

视图模型当然是大部分有趣代码所在的位置,甚至主要的是单个方法_StartCountdown() ,它实现了实际的倒计时:

ViewModel.cs:

 class ViewModel { private async void _StartCountdown() { Running = true; // NOTE: UTC times used internally to ensure proper operation // across Daylight Saving Time changes. An IValueConverter can // be used to present the user a local time. // NOTE: RemainingTime is the raw data. It may be desirable to // use an IValueConverter to always round up to the nearest integer // value for whatever is the least-significant component displayed // (eg minutes, seconds, milliseconds), so that the displayed // value doesn't reach the zero value until the timer has completed. DateTime startTime = DateTime.UtcNow, endTime = startTime + Duration; TimeSpan remainingTime, interval = TimeSpan.FromMilliseconds(100); StartTime = startTime; remainingTime = endTime - startTime; while (remainingTime > TimeSpan.Zero) { RemainingTime = remainingTime; if (RemainingTime < interval) { interval = RemainingTime; } // NOTE: arbitrary update rate of 100 ms (initialized above). This // should be a value at least somewhat less than the minimum precision // displayed (eg here it's 1/10th the displayed precision of one // second), to avoid potentially distracting/annoying "stutters" in // the countdown. await Task.Delay(interval); remainingTime = endTime - DateTime.UtcNow; } RemainingTime = TimeSpan.Zero; StartTime = null; Running = false; } private TimeSpan _duration; public TimeSpan Duration { get { return _duration; } set { _UpdateField(ref _duration, value); } } private DateTime? _startTime; public DateTime? StartTime { get { return _startTime; } private set { _UpdateField(ref _startTime, value); } } private TimeSpan _remainingTime; public TimeSpan RemainingTime { get { return _remainingTime; } private set { _UpdateField(ref _remainingTime, value); } } private bool _running; public bool Running { get { return _running; } private set { _UpdateField(ref _running, value, _OnRunningChanged); } } private void _OnRunningChanged(bool obj) { _startCountdownCommand.RaiseCanExecuteChanged(); } private readonly DelegateCommand _startCountdownCommand; public ICommand StartCountdownCommand { get { return _startCountdownCommand; } } public ViewModel() { _startCountdownCommand = new DelegateCommand(_StartCountdown, () => !Running); } public event PropertyChangedEventHandler PropertyChanged; private void _UpdateField(ref T field, T newValue, Action onChangedCallback = null, [CallerMemberName] string propertyName = null) { if (EqualityComparer.Default.Equals(field, newValue)) { return; } T oldValue = field; field = newValue; onChangedCallback?.Invoke(oldValue); PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } } 

如评论中所述,上述内容将按原样运行,但如果您需要特定输出,则使用IValueConverter实现来调整输出以满足用户特定需求是有用的。 以下是一些例子:

UtcToLocalConverter.cs:

 class UtcToLocalConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { if (value == null) return null; if (value is DateTime) { DateTime dateTime = (DateTime)value; return dateTime.ToLocalTime(); } return Binding.DoNothing; } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { if (value == null) return null; if (value is DateTime) { DateTime dateTime = (DateTime)value; return dateTime.ToUniversalTime(); } return Binding.DoNothing; } } 

TimeSpanRoundUpConverter.cs:

 class TimeSpanRoundUpConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { if (!(value is TimeSpan && parameter is TimeSpan)) { return Binding.DoNothing; } return RoundUpTimeSpan((TimeSpan)value, (TimeSpan)parameter); } private static TimeSpan RoundUpTimeSpan(TimeSpan value, TimeSpan roundTo) { if (value < TimeSpan.Zero) return RoundUpTimeSpan(-value, roundTo); double quantization = roundTo.TotalMilliseconds, input = value.TotalMilliseconds; double normalized = input / quantization; int wholeMultiple = (int)normalized; double fraction = normalized - wholeMultiple; return TimeSpan.FromMilliseconds((fraction == 0 ? wholeMultiple : wholeMultiple + 1) * quantization); } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { throw new NotImplementedException(); } } 

当然,还有一些XAML用于定义UI(其中没有UI元素具有名称,代码隐藏也不需要显式访问任何UI元素):

MainWindow.xaml:

        00:00:01