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);
}
}