C# 从可观察到的采集开始,而不是立即采集

C# 从可观察到的采集开始,而不是立即采集,c#,wpf,multithreading,observablecollection,begininvoke,C#,Wpf,Multithreading,Observablecollection,Begininvoke,在我的代码中,我订阅了发生在不同线程上的事件。每次发生此事件时,我都会收到一个发布到可观察集合的字符串: Dispatcher currentDispatcher = Dispatcher.CurrentDispatcher; var SerialLog = new ObservableCollection<string>(); private void hitStation_RawCommandSent(object sender, StringEvent

在我的代码中,我订阅了发生在不同线程上的事件。每次发生此事件时,我都会收到一个发布到可观察集合的字符串:

    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);
    }
我遇到的问题是,绑定到我的SerialLog的ListBox只有在HitBall方法完成时才会更新。我期待着看到一堆来自预赛的更新,暂停,然后是来自HitBall的更多更新


我尝试了几个DispatcherPriority参数,但它们似乎没有任何效果。

您可能不会看到来自
PrepareHit
的更新,除非有上下文切换,并且无法保证上下文切换何时发生(除非阻止当前线程,否则会增加发生上下文切换的可能性)

如iCe所述,如果您在UI线程上执行此操作,则可能会阻塞UI。当您调用
线程时,UI是否会阻塞/冻结。请等待
?如果没有,请继续阅读以下内容:

更新:
我想不出任何不影响并发性的东西……如果不影响并发性,您可以尝试提高
BeginInvoke

顺便说一句,看起来
渲染
优先级低于
正常
优先级:

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

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

正常设置枚举值 is 9。在以下位置处理操作: 正常优先级。这是典型的 应用程序优先级

发送 枚举值为10 先处理后处理 异步操作。这是 最高优先权


您可能看不到来自
PrepareHit
的更新,除非存在上下文切换,并且无法保证上下文切换何时发生(除非您阻止当前线程,这将增加上下文切换发生的可能性)

如iCe所述,如果您在UI线程上执行此操作,则可能会阻塞UI。当您调用
线程时,UI是否会阻塞/冻结。请等待
?如果没有,请继续阅读以下内容:

更新:
我想不出任何不影响并发性的东西……如果不影响并发性,您可以尝试提高
BeginInvoke

顺便说一句,看起来
渲染
优先级低于
正常
优先级:

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

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

正常设置枚举值 is 9。在以下位置处理操作: 正常优先级。这是典型的 应用程序优先级

发送 枚举值为10 先处理后处理 异步操作。这是 最高优先权


我想你是在妨碍自己

UI线程正在线程处等待。等待,BeginInvoke将操作发送到Dispatcher,但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,那么使用此实现就不再需要它了。

我认为您正在阻止自己

UI线程正在线程处等待。等待,BeginInvoke将操作发送到Dispatcher,但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);
      }
 }

如果线程的预期用途也是如此。等待(1000)是等待事件刷新UI,使用此实现它不再需要。

是否可以像需要在ViewModel上引发PropertyChanged事件那样简单?

是否可以像需要在ViewModel上引发PropertyChanged事件那样简单?

是否有替代解决方案看到添加到列表中的项目了吗?@Padu,尝试增加BeginInvoke的优先级作为旁注,渲染优先级低有很好的理由:渲染优先级低于数据绑定意味着(由于调度程序的排队性质)当多个数据绑定属性同时更改时,不会导致控件多次重新呈现。类似地,“正常”操作是您的常规代码操作-通常会更改绑定指向的对象,因此应该允许在更新绑定之前完成所有操作。这就是为什么在WPF中将长时间运行的批更新内容从UI线程中推出更为重要的原因。另外:如果
HitTest
方法正在运行在Dispatcher线程上,它将被允许在Dispatcher队列上的下一项中断它之前完成。因此,如果
HitTest
在错误的线程上,则使用什么优先级无关紧要。是否有其他解决方案,可以在项目到达时看到添加到列表中的项目?@Padu,尝试增加优先级BEGININVOKEY作为旁注,呈现优先级低有很好的理由:呈现优先级低于数据绑定意味着(由于调度程序的排队特性),当多个数据绑定属性同时更改时,不会导致控件多次重新呈现。类似地,“正常”操作是您的通用代码操作-这将
 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);
      }
 }