gpt4 book ai didi

c# - 从后台线程引发的事件更新 UI

转载 作者:行者123 更新时间:2023-11-30 17:34:04 27 4
gpt4 key购买 nike

我的 WPF 应用程序在后台线程上启动长时间运行的函数,通常是通过按钮单击/命令,例如

StartCommand = new RelayCommand(async o => await StartAsync(), o => true);

...

private async Task StartAsync()
{
await Task.Run(() => LongRunningFunction());
}

这些长时间运行的函数引发各种事件以向用户报告进度、更新 UI 值等。 View 模型处理此类事件并更新绑定(bind)属性,例如:

private void LongRunningProcessProgressChanged(object sender, ProgressEventArgs e)
{
StatusMessageText = string.Format("Progress {0}%", e.Progress);
}

大多数时候这工作正常,但偶尔我会遇到关于从后台线程更新 UI 的常见异常(“调用线程无法访问此对象,因为另一个线程拥有它”),所以我必须包装Dispatcher.Invoke(...) 中的代码。我还没有真正发现何时需要或不需要这样做的模式,所以任何人都可以阐明它吗?

老实说,我很惊讶上面的代码能正常工作。断点确认这些事件处理程序在工作线程上运行,而不是在 UI 线程上运行,那么为什么我一直没有看到异常?是否与正在更新的属性类型有关?

编辑 人们正在对我已经知道的问题提出答案。再次阅读我的问题,我可能会让读者对“大多数时候这工作正常但偶尔我会遇到通常的异常”部分感到困惑。我并不是说这是一个间歇性问题——我真正的意思是我的一些 VM 在它们各自的进度事件处理程序中更新绑定(bind)属性没有问题,而其他 VM 有。我怀疑它与属性(property)类型有关,例如更新字符串属性有效,但不适用于 ObservableCollection。

我的问题更像是一个好奇的问题,即为什么一些绑定(bind)属性可以从 b/g 线程更新,而其他则不能。

最佳答案

当您从后台线程更新 UI 时,您的代码应始终抛出异常。您并不总是看到异常,因为异常发生在后台线程中并保持 unobserved .对于此类异常(exception)情况

.. TPL needs to backstop these exceptions and hold on to them until such time that they can be thrown again when the consuming code accesses the task.

因此,您不会在后台任务抛出异常后立即看到异常。


更新

This answer阐明了从另一个线程访问控件时的常见情况。关于您描述的问题,它实际上取决于您绑定(bind)的属性类型,如 MSDN forum 所述:

Data binding to primitive types is basically type safe, since the binding mechanism, internally, uses the dispatcher to marshal back to the UI thread for you.

However, you need to take care with collections. For example, ObservableCollection will not handle this, so you need to make changes to the collection on the UI thread.

在此blog post您可以找到更多详细信息。

关于c# - 从后台线程引发的事件更新 UI,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42997453/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com