WPF使用Task异步获取数据后ContextMenu添加MenuItem不显示问题
问题原因
- WinForm、WPF等主流UI框架均有强制规则:所有UI控件的属性修改、集合变更操作必须在UI主线程执行,后台线程执行UI操作时,既可能直接抛出跨线程访问异常,也可能无报错但变更不生效,你遇到的就是第二种情况。
Task.Run会将GetItems调度到后台线程执行,而ContinueWith的回调默认也会在后台线程运行,你后续向ContextMenu添加MenuItem的代码在后台线程执行时,修改不会同步到UI渲染层,自然看不到新增的菜单项。- 冗余写法问题:你已经使用
await关键字,完全不需要额外搭配ContinueWith获取结果,await本身既可以直接拿到Task的返回值,还会默认将后续代码调度回调用前的同步上下文(即UI线程)执行。 - 额外注意:你原代码中给MenuItem赋值的
.Heder属于拼写错误,正确的属性名为.Header,如果没有修正也会导致菜单项文本不显示。
修复方案
直接用await接收Task.Run的执行结果即可,不需要多余的ContinueWith,示例代码如下:
' 方法必须标记Async修饰符 Private Async Sub YourMenuInitMethod() Dim Menu = MyContextMenu ' await自动将后续代码调度回UI线程执行 Dim items = Await Task.Run(Function() GetItems()) For Each item In items Menu.Add(New MenuItem With {.Header = item.Name}) Next End Sub
如果你一定要保留ContinueWith写法,需要手动指定回调的调度器为UI线程同步上下文:
Dim items = Await Task.Run(AddressOf GetItems).ContinueWith( Function(x) x.Result, TaskScheduler.FromCurrentSynchronizationContext() )
内容的提问来源于stack exchange,提问作者Yossi Polak
相关产品推荐
相关产品推荐

