2

ユーザーが 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();ボタンのクリックで呼び出されます

誰かが私を正しい方向に向けることができますか?

4

3 に答える 3

12

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}"/>
于 2012-04-19T02:20:02.503 に答える
2

簡単な方法は、タイマー (ストップウォッチではなく) を使用することです。タイマーは、間隔を設定し、各ティックでメソッドを呼び出すことができるコンポーネントです。ストップウォッチのデータ メンバーと組み合わせると、たとえば、ストップウォッチの Elapsed プロパティに (ShowElapsedTime メソッドで行うように) 50 ミリ秒ごとにアクセスできます。

その主な問題は、タイマーが完全に時間を計っていないことと、ラベルのテキストの更新が不安定になることです。

別のアプローチとして、スレッドを使用して UI がロックダウンするのを防ぎますが、メイン スレッド以外のスレッドからラベル テキストを変更すると、例外が発生します。

その例外をバイパスすることはできますが、より良い方法は BackgroundWorker を使用することです。

BGWorker は別のスレッドでタスクを実行し、進行状況を報告してメイン スレッドで呼び出すことができます。

本当に完璧にしたい場合は、プロパティ ElapsedTime を持つ INotifyPropertyChanged を実装するクラスと、プライベートな StopWatch データ メンバーを用意してください。このクラスは、次の方法で BackgroundWorker を使用します。

担当者:

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 イベントをサブスクライブします。ただし、stopWatch.Elapsed プロパティの代わりにクラスの ElapsedTime プロパティを使用します。

于 2012-04-19T02:07:44.787 に答える
1

ShowElapsedTime定期的に呼び出すタイマーが必要です。例については、 WPF タイマーのカウントダウンを参照してください。

于 2012-04-19T02:06:35.953 に答える