如何在Windows App SDK(C#)中从后台线程同步更新主线程?
解答:后台线程同步等待UI线程执行更新
需求可行吗?
可行,但DispatcherQueue.TryEnqueue本身做不到,得换个方式实现同步等待的逻辑。
为啥直接用TryEnqueue不行?
TryEnqueue是异步投递任务:它只负责把更新UI的任务扔进UI线程的队列,然后立刻返回,根本不会等任务执行完。你要的是后台线程等UI更新完再查数量,这玩意儿满足不了。- 对比Swift的
DispatchQueue.main.sync:sync会阻塞当前线程,直到主线程把任务跑完、结果返回;但TryEnqueue从设计上就没做阻塞等待的逻辑,完全是两个路子。
怎么实现同步UI更新?
方案1:用TaskCompletionSource手动做等待
把异步的TryEnqueue包装成可等待的任务,后台线程就能等UI操作完成了,代码示例:
// 后台线程里的代码 var tcs = new TaskCompletionSource<int>(); // 把UI操作丢去UI线程 this.DispatcherQueue.TryEnqueue(() => { // 更新你的ObservableCollection yourCollection.Add(newItem); // 告诉后台线程:我做完了,把数量传回去 tcs.SetResult(yourCollection.Count); }); // 阻塞后台线程,等UI操作完拿结果 int newCount = await tcs.Task; // 如果不能用await,也可以用.Result,但要注意:要是UI线程此刻也在等后台线程,会直接死锁
方案2:WPF环境直接用Dispatcher.Invoke
如果是WPF项目,Dispatcher.Invoke本身就是同步阻塞的,和Swift的sync一模一样,直接用就行:
// 后台线程执行 int newCount = (int)this.Dispatcher.Invoke(() => { yourCollection.Add(newItem); return yourCollection.Count; });
重要提醒
- 死锁大坑:要是UI线程此时正在等后台线程的结果,后台线程又卡着等UI线程,直接就死锁了,这种场景绝对不能用同步等待。
- 性能代价:后台线程等着UI线程干活,会浪费并发能力,能异步处理(比如用回调、事件通知结果)就尽量别用同步。
内容的提问来源于stack exchange,提问作者Duncan Groenewald
相关产品推荐
相关产品推荐

