4

DispatcherTimer構文をスレッドタイマーに変換する際に問題が発生しました。アプリケーションを突然実行すると、エラーなしでシャットダウンします。

基本的に、タイマーに5秒ごとに2つのメソッドを実行させたいです。

編集:2つの方法でUIを更新しています。 UI表示で多くのフリーズと遅延が発生する必要があるため、DispatcherTimerを削除しようとしています。

ディスパッチャタイマーコード:

timerW = new DispatcherTimer();
    timerW.Tick += new EventHandler(timerW_Tick);
    timerW.Interval = new TimeSpan(0, 0, 5000);
    timerW.Start();



 private void timerW_Tick(object sender, EventArgs e)
        {
            DisplayWegingInfo();
            CaculateTimen();
        }

System.Threadingタイマーのコード:

public void InitializeDispatcherTimerW()
    {
        TimerCallback callback = MyTimerCallBack;
        timerW = new Timer(callback);

        timerW.Change(0, 5000);
    }

    private void MyTimerCallBack(object state)
    {
        DisplayWegingInfo();
        CaculateTime();
    }

ありがとう。

4

5 に答える 5

3

最も可能性の高い問題は、タイマーコールバックのメソッドでUIを更新していることです。これはUIスレッドからのみ可能であり、タイマーはバックグラウンドスレッドで実行されます。

に固執することをお勧めしますDispatcherTimer

別の解決策は、コードを少し分割することです。作業量の多いコードを他のメソッドに抽出し、それらをバックグラウンドスレッドで実行し、その後UIスレッドからUIを更新します。

このようなもの:

private void MyTimerCallBack(object state)
{
    LongCalculationsThatDontNeedTheUI();
    _dispatcherUIThread.Invoke(new Action(UpdateUI));
}
于 2012-04-16T15:07:38.760 に答える
2

DisplayWedgingInfoという名前で判断すると、このメソッドはUIを更新すると思いますか?System.Threading.Timerは、UIスレッドとは異なるスレッドで実行されるため、そのスレッドからUIを更新できるようにするには、Dispatcherを使用してこれらの呼び出しをスレッドにマーシャリングする必要がありますDispatcher::[Begin]Invoke

したがって、UI要素に触れない高価な作業はそのままにしておくことができますが、UI操作の場合は次のようにします。

string someValue = this.SomeExpensiveOperation();

this.Dispatcher.BeginInvoke(
    DispatcherPriority.Background,
    new Action(() => 
   { 
          this.myControl.Text = someValue; 
   }));

呼び出しが発生したときに行われる可能性のあるUIインタラクション/レンダリングが中断される可能性があることを指摘しておく必要があります。実行はメインスレッドで行われるため、これは避けられません。あなたを使用することによりDispatcherPriority.Background、少なくとも、ユーザーがその時点で提供する可能性のある入力よりも低く保つ優先度で更新をスケジュールします。ただし、ペナルティなしでUIを大幅に更新できるとは期待しないでください。これを行う必要がある場合は、優先度の高い複数の呼び出しをキューに入れてBackground、必要に応じて入力などの優先度の高いもので発生できるようにするのが最善です。

于 2012-04-16T15:11:07.593 に答える
0

データの取得/計算データ表示から分離する必要があると思います。

Danielが指摘しているように、GUIの更新はすべてDispatcherスレッドで実行する必要があるため、最も簡単な方法はを使用することDispatcherTimerです。

ただし、使用DispatcherTimerするということは、タイマーコールバックのすべてがGUIスレッドで行われることを意味します。かなりの時間がかかる操作がある場合、これは良くありません。あなたが見つけたように、GUIは途切れてロックします。

あなたは時間を取っているものを理解する必要があります。あなたの他の質問から、私はそれがSQL検索であると推測します。この場合、(を使用して)別のスレッドで実際の取得System.Threading.Timerを実行し、結果が得られたら、を使用してGUIスレッドにマーシャリングして表示を更新することをお勧めします。Dispatcher.BeginInvoke()

于 2012-04-16T15:19:20.570 に答える
0

私は2つのことをチェックします:1。他の人が言っているように、UIを更新している場合は、ディスパッチャに呼び出していることを確認してください。UIはUIスレッドからのみ更新できます。データバインディングを使用している場合でも、タイマースレッドがUIにデータバインドされている値を更新すると、UIにアクセスしている間違ったスレッドとして「カウント」されます。

  1. 常にtry..catchブロックでtimeerコールバックを保護してください。未処理の例外に対する.Netのデフォルトの動作は、プロセスを終了することです。私は多くの「ただやめる」のを見てきました。本当の原因はタイマースレッドやワーカースレッドでの例外処理ではありませんでした。(実際、間違ったスレッドからUIを操作しようとすると、WPFは例外をスローするはずです。そのため、例外が発生している可能性があり、ハンドラーがないためにプログラムが終了します)
于 2012-04-16T15:21:40.710 に答える
-3

単にバックグラウンドスレッドを使用してイベントをディスパッチしてみませんか?

  CancellationTokenSource cts = new CancellationTokenSource();
  Task.Factory.StartNew(() =>
     {
          while(!cts.IsCancellationRequested)
          {
               Thread.Sleep(5000);

               this.Dispatcher.BeginInvoke(new Action(() =>
                  {
                       DisplayWegingInfo();
                       CalculateTimen();
                  }), null);
          }
     });
于 2012-04-16T15:09:24.827 に答える