0

私のコードでは、別のスレッドで発生するイベントをサブスクライブしています。このイベントが発生するたびに、監視可能なコレクションに投稿される文字列を受け取ります。

    Dispatcher currentDispatcher = Dispatcher.CurrentDispatcher;
    var SerialLog = new ObservableCollection<string>();

    private void hitStation_RawCommandSent(object sender, StringEventArgs e)
    {
        string command = e.Value.Replace("\r\n", "");
        Action dispatchAction = () => SerialLog.Add(command);
        currentDispatcher.BeginInvoke(dispatchAction, DispatcherPriority.Render);
    }

以下のコードは私のビュー モデルにあります (コード ビハインドにある可能性がありますが、この場合は問題ではありません)。「hitstation.PrepareHit」を呼び出すと、上記のイベントが数回呼び出され、待機してから「hitStation.HitBall」を呼び出すと、上記のイベントがさらに数回呼び出されます。

    private void HitBall()
    {
        try
        {
            try
            {
                Mouse.OverrideCursor = Cursors.Wait;

                //prepare hit
                hitStation.PrepareHit(hitSpeed);

                Thread.Wait(1000);
                PlayWarning();

                //hit
                hitStation.HitBall(hitSpeed);
            }
            catch (TimeoutException ex)
            {
                MessageBox.Show("Timeout hitting ball: " + ex.Message);
            }
        }
        finally
        {
            Mouse.OverrideCursor = null;
        }
    }

私が抱えている問題は、SerialLog にバインドされている ListBox が、HitBall メソッドが終了したときにのみ更新されることです。私は、PrepareHit からの一連の更新、一時停止、そして HitBall からのさらに多くの更新を期待していました。

DispatcherPriority 引数をいくつか試しましたが、効果がないようです。

4

3 に答える 3

4

自分をブロックしていると思います。

UI スレッドは Thread.Wait で待機しています。BeginInvoke はアクションをディパッチャーに送信しますが、UI スレッドは待機中です。そのため、UI の更新は、HitBall が終了した後、つまり UI スレッドが処理を終了したときにのみ行われます。

これを回避するには、別のスレッドで HitBall メソッドのコードを開始し、UI を解放する必要があります。

 private void HitBall() 
 { 
     try {

         Mouse.OverrideCursor = Cursors.Wait;
         Dispatcher dispatcher = Dispatcher.CurrentDispatcher;

         Action hitOperations = () =>
         {
             hitStation.PrepareHit(hitSpeed);

             Thread.Wait(1000);

             //Only needed if PlayWarning needs access to UI Thread
             dispatcher.Invoke(() => PlayWarning());

             hitStation.HitBall(hitSpeed);

             dispatcher.Invoke(() => Mouse.OverrideCursor = null);
          };

          //Free the UI from work, start operations in a background thread
          hitOperations.BeginInvoke(null, null);

      }
      catch (TimeoutException ex)
      {
          MessageBox.Show("Timeout hitting ball: " + ex.Message);
      }
 }

また、Thread.Wait(1000) の使用目的が、イベントが UI を更新するのを待つことであった場合、この実装では必要なくなりました。

于 2010-04-27T23:21:21.627 に答える
1

ViewModel で PropertyChanged イベントを発生させる必要があるのと同じくらい簡単なことでしょうか?

于 2010-04-28T15:10:13.057 に答える
0

PrepareHitコンテキストの切り替えがなく、コンテキストの切り替えがいつ発生するかが保証されない限り、更新はおそらく表示されません (現在のスレッドをブロックして、コンテキストの切り替えが発生する可能性が高くなる場合を除きます)。

UIスレッドでこれを行っている場合、iCeが述べたように、UIをブロックしている可能性があります。を呼び出すと、UI がブロックまたはフリーズしますThread.Waitか? そうでない場合は、以下を読み進めてください。

更新:
同時実行性を損なわないものは考えられません...同時実行性を損なうことなく、次の優先度を上げることができますBeginInvoke: http://msdn.microsoft.com/en-us/library/system.windows.threading .dispatcherpriority.aspx

currentDispatcher.BeginInvoke(dispatchAction, DispatcherPriority.Send);

ちなみに、Render優先度は優先度よりも低いようですNormal

Render 列挙値は 7 です。操作はレンダリングと同じ優先度で処理されます。

DataBind 列挙値は 8 です。操作は、データ バインディングと同じ優先度で処理されます。

Normal 列挙値は 9 です。操作は通常の優先度で処理されます。これは、典型的なアプリケーションの優先度です。

Send 列挙値は 10 です。操作は、他の非同期操作の前に処理されます。これは最優先事項です。

于 2010-04-27T22:28:44.997 に答える