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 将操作发送到 dipatcher,但 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除非有上下文切换并且无法保证何时会发生上下文切换,否则您可能不会看到更新(除非您阻塞当前线程并且这会增加发生上下文切换的可能性)。

正如 iCe 提到的,如果您在 UI 线程上执行此操作,那么您可能会阻塞您的 UI。当您打电话时,您的 UI 是否会阻塞/冻结Thread.Wait?如果没有,则继续阅读以下内容:

更新:
我想不出任何不会影响并发性的东西......在不影响并发性的情况下,您可以尝试提高以下优先级:http BeginInvoke: //msdn.microsoft.com/en-us/library/system.windows.threading .dispatcherpriority.aspx

currentDispatcher.BeginInvoke(dispatchAction, DispatcherPriority.Send);

顺便说一句,看起来Render优先级低于Normal优先级:

Render 枚举值为 7。操作的处理优先级与渲染相同。

DataBind 枚举值为 8。操作的处理优先级与数据绑定相同。

正常 枚举值为 9。操作以正常优先级处理。这是典型的应用程序优先级。

Send 枚举值为 10。操作在其他异步操作之前处理。这是最高优先级。

于 2010-04-27T22:28:44.997 回答