尝试更新 ViewModel 中的 Ui 属性时 DispatcherQueue null

Posted

技术标签:

【中文标题】尝试更新 ViewModel 中的 Ui 属性时 DispatcherQueue null【英文标题】:DispatcherQueue null when trying to update Ui property in ViewModel 【发布时间】:2021-12-20 16:40:06 【问题描述】:

在桌面应用程序中的 WinUI 3 中,我有一个要更新的属性,该属性通过 x:Bind 绑定到 UI。

我想像在 WPF 中那样使用Dispatcher 来进入 UI 线程,并避免在更新道具时出现线程错误:

System.Runtime.InteropServices.COMException: 'The application called an interface that was marshalled for a different thread. (0x8001010E (RPC_E_WRONG_THREAD))'

当我尝试时,我只是不确定如何在 WinUI 3 中做到这一点

DispatcherQueue.GetForCurrentThread().TryEnqueue(() =>

    AeParty.OnSyncHub = false; // Prop bound in ui using x:Bind
);

我收到此错误

DispatcherQueue.GetForCurrentThread() 为空

我也试过了:

this.DispatcherQueue.TryEnqueue(() =>

    AeParty.OnSyncHub = false;
);

但它不会编译:

然后我发现this GitHub问题,所以我尝试了:

SynchronizationContext.Current.Post((o) =>

    AeParty.OnSyncHub = false;

, null);

这可行,但为什么我不能在我的 VM 中使用 Dispatcher 进入 UI 线程?

【问题讨论】:

【参考方案1】:

DispatcherQueue.GetForCurrentThread() 仅在实际具有DispatcherQueue 的线程上调用时返回DispatcherQueue。如果您在后台线程上调用它,则确实不会返回 DispatcherQueue

所以诀窍是在 UI 线程上调用该方法并将返回值存储在一个变量中,然后您可以从后台线程中使用该变量,例如:

public sealed partial class MainWindow : YourBaseClass

    public MainWindow()
    
        this.InitializeComponent();
    

    public ViewModel ViewModel  get;  = new ViewModel();


public class ViewModel : INotifyPropertyChanged

    private readonly DispatcherQueue _dispatcherQueue = DispatcherQueue.GetForCurrentThread();

    public ViewModel()
    
        Task.Run(() => 
        
            for (int i = 0; i < 10; i++)
            
                string val = i.ToString();
                _dispatcherQueue.TryEnqueue(() =>
                
                    Text = val;
                );
                Thread.Sleep(2000);
            
        );

    
    private string _text;
    public string Text
    
        get  return _text; 
        set  _text = value; NotifyPropertyChanged(nameof(Text)); 
    

    public event PropertyChangedEventHandler PropertyChanged;
    private void NotifyPropertyChanged([CallerMemberName] string propertyName = "")
    
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    

【讨论】:

以上是关于尝试更新 ViewModel 中的 Ui 属性时 DispatcherQueue null的主要内容,如果未能解决你的问题,请参考以下文章

从事件更新 Viewmodel - PropertyChangedEventHandler 为空?

来自事件处理程序的 ReactiveUI MVVM 更新属性

更新 ViewModel 时如何防止 Kendo UI Grid 多次重新绑定

如何在viewmodel中的异步任务后更新UI

为啥将 ViewModel 添加到我的 SwiftUI 应用程序后我的 UI 没有更新?

模型更改时刷新 ViewModel 的所有属性的数据绑定的好方法