简体   繁体   English

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

[英]Display the running time of part of a program in a label

I am trying to have a label display the time it takes the user to complete a task which starts at 00:00:00 and goes up in shown millisecond increments from there.我试图让标签显示用户完成从 00:00:00 开始的任务所花费的时间,并以显示的毫秒增量从那里开始。 So far I have this:到目前为止,我有这个:

    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(); is called on a button click单击按钮时调用

Can someone point me in the right direction?有人可以指出我正确的方向吗?

I'd recommend taking an MVVM approach.我建议采用 MVVM 方法。 Have your TextBlock bind to a string member on your ViewModel.将 TextBlock 绑定到 ViewModel 上的字符串成员。 In your ViewModel you can use a DispatcherTimer to set the the time elapsed.在您的 ViewModel 中,您可以使用 DispatcherTimer 来设置经过的时间。 The DispatcherTimer fires its callback on the UI thread so you don't need to invoke to the UI thread. DispatcherTimer 在 UI 线程上触发其回调,因此您无需调用 UI 线程。

Code:代码:

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: XAML:

<TextBlock Text="{Binding TimeElapsed}"/>

The simple way would be using a Timer (not a stopwatch).简单的方法是使用计时器(不是秒表)。 The timer is a component which you can set intervals of and invoke a method on each tick.计时器是一个组件,您可以在每个刻度上设置间隔并调用一个方法。 Combine with a data member of a stopwatch and you can access the stopwatch's Elapsed property (as you do in your ShowElapsedTime method) every 50 milliseconds, for example.例如,结合秒表的数据成员,您可以每 50 毫秒访问一次秒表的 Elapsed 属性(就像您在 ShowElapsedTime 方法中所做的那样)。

The main problem with that would be that the timer isn't perfectly timed and will also be bumpy on the label text update.这样做的主要问题是计时器不是完全定时的,并且在标签文本更新时也会出现颠簸。

A different approach would be using a thread to prevent the UI from locking down, but then if you changed label text from a thread other than your main thread - you get an exception.一种不同的方法是使用线程来防止 UI 锁定,但是如果您从主线程以外的线程更改了标签文本,则会出现异常。

You CAN bypass that exception, but the better way would be using a BackgroundWorker.您可以绕过该异常,但更好的方法是使用 BackgroundWorker。

The BGWorker will perform the task in a different thread and you can let it report progress, to be invoked in the main thread. BGWorker 将在不同的线程中执行任务,您可以让它报告进度,在主线程中调用。

If you really want to be perfect about it, have a class that implements INotifyPropertyChanged that has a property ElapsedTime, and a private StopWatch data member.如果您真的想完美解决它,请使用一个实现 INotifyPropertyChanged 的​​类,该类具有一个属性 ElapsedTime 和一个私有的 StopWatch 数据成员。 The class will use a BackgroundWorker in the following manner.该类将按以下方式使用 BackgroundWorker。

At the 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;
                              };

When you want to start the worker (aka start the timer):当您想启动工作程序(又名启动计时器)时:

stopwatch.Start();
_worker.RunWorkerAsync();

And when you want to stop the worker (aka stop the timer):当你想停止工作人员(又名停止计时器)时:

stopwatch.Reset();
_worker.CancelAsync();

The class itself will have a Start and Stop methods that will interact with the worker (data member).类本身将有一个 Start 和 Stop 方法,它们将与工作人员(数据成员)进行交互。

Finally, you can BIND the label text to your class's ElapsedTime property.最后,您可以将标签文本绑定到类的 ElapsedTime 属性。 Or subscribe to an ElapsedTimeChanged event with your ShowElapsedTime method, except it will then use your class's ElapsedTime property instead of the stopWatch.Elapsed property.或者使用您的 ShowElapsedTime 方法订阅 ElapsedTimeChanged 事件,但它将使用您的类的 ElapsedTime 属性而不是 stopWatch.Elapsed 属性。

You need a timer that will call ShowElapsedTime periodically.您需要一个定期调用ShowElapsedTime的计时器。 See WPF timer countdown for an example.有关示例,请参阅WPF 计时器倒计时

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM