显示标签中程序的一部分的运行时间

时间:2012-04-19 01:41:33

标签: c# wpf

我正在尝试让标签显示用户完成任务所需的时间。因此标签从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所();按下按钮时调用

有人能指出我正确的方向吗?

3 个答案:

答案 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