我正在尝试让标签显示用户完成任务所需的时间。因此标签从00:00:00开始,并从那里以毫秒为增量上升。到目前为止,我有这个:
private void startTimer()
{
stopWatch.Start();
Dispatcher.BeginInvoke(DispatcherPriority.Render, new ThreadStart(ShowElapsedTime));
}
void ShowElapsedTime()
{
TimeSpan ts = stopWatch.Elapsed;
lblTime.Text = String.Format("{0:00}:{1:00}.{2:00}", ts.Minutes, ts.Seconds, ts.Milliseconds / 10);
}
startTimer所();按下按钮时调用
有人能指出我正确的方向吗?
答案 0 :(得分:11)
我建议采用MVVM方法。让TextBlock绑定到ViewModel上的字符串成员。在ViewModel中,您可以使用DispatcherTimer来设置经过的时间。 DispatcherTimer在UI线程上触发其回调,因此您不需要调用UI线程。
代码:
public class ViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public string TimeElapsed {get;set;}
private DispatcherTimer timer;
private Stopwatch stopWatch;
public void StartTimer()
{
timer = new DispatcherTimer();
timer.Tick += dispatcherTimerTick_;
timer.Interval = new TimeSpan(0,0,0,0,1);
stopWatch = new Stopwatch();
stopWatch.Start();
timer.Start();
}
private void dispatcherTimerTick_(object sender, EventArgs e)
{
TimeElapsed = stopWatch.Elapsed.TotalMilliseconds; // Format as you wish
PropertyChanged(this, new PropertyChangedEventArgs("TimeElapsed"));
}
}
XAML:
<TextBlock Text="{Binding TimeElapsed}"/>
答案 1 :(得分:2)
简单的方法是使用计时器(不是秒表)。 计时器是一个组件,您可以在每个tick上设置间隔并调用方法。例如,与秒表的数据成员组合,您可以每隔50毫秒访问秒表的Elapsed属性(就像在ShowElapsedTime方法中那样)。
主要的问题是计时器不是完美的定时,并且在标签文本更新时也会出现颠簸。
另一种方法是使用线程来阻止UI锁定,但是如果你从主线程以外的线程更改标签文本 - 你会得到一个例外。
您可以绕过该异常,但更好的方法是使用BackgroundWorker。
BGWorker将在另一个线程中执行任务,您可以让它报告进度,在主线程中调用。
如果你真的想要完善它,请有一个实现具有属性ElapsedTime的INotifyPropertyChanged的类,以及一个私有的StopWatch数据成员。该类将以下列方式使用BackgroundWorker。
在ctor:
this._stopwatch = new Stopwatch();
this._worker = new BackgroundWorker {WorkerReportsProgress = true, WorkerSupportsCancellation = true};
_worker.DoWork += (s, e) =>
{
while (!_worker.CancellationPending)
{
_worker.ReportProgress(0, watch.Elapsed);
Thread.Sleep(1);
}
};
_worker.ProgressChanged += (s, e) =>
{
this.ElapsedTime = (TimeSpan)e.UserState;
};
当你想要启动工作者时(也就是启动计时器):
stopwatch.Start();
_worker.RunWorkerAsync();
当你想要停止工人时(也就是停止计时器):
stopwatch.Reset();
_worker.CancelAsync();
类本身将有一个Start和Stop方法,它们将与worker(数据成员)进行交互。
最后,您可以将标签文本绑定到类的ElapsedTime属性。 或者使用您的ShowElapsedTime方法订阅ElapsedTimeChanged事件,不过它将使用您的类的ElapsedTime属性而不是stopWatch.Elapsed属性。
答案 2 :(得分:1)
您需要一个定期调用ShowElapsedTime
的计时器。有关示例,请参阅WPF timer countdown。