简单的方法是使用计时器(不是秒表)。计时器是一个组件,您可以设置间隔并在每个刻度上调用一个方法。例如,结合秒表的数据成员,您可以每 50 毫秒访问一次秒表的 Elapsed 属性(就像您在 ShowElapsedTime 方法中所做的那样)。
这样做的主要问题是计时器的计时不完美,并且在标签文本更新时也会出现颠簸。
另一种方法是使用线程来防止 UI 锁定,但是如果您从主线程以外的线程更改标签文本 - 您会遇到异常。
您可以绕过该异常,但更好的方法是使用 BackgroundWorker。
BGWorker 将在不同的线程中执行任务,您可以让它报告进度,以便在主线程中调用。
如果您真的想做到完美,请拥有一个实现 INotifyPropertyChanged 的类,该类具有属性 ElapsedTime 和私有 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 方法。
最后,您可以将标签文本绑定到类的 ElapsedTime 属性。或者使用您的 ShowElapsedTime 方法订阅 ElapsedTimeChanged 事件,除非它将使用您的类的 ElapsedTime 属性而不是 stopWatch.Elapsed 属性。