问题描述
在桌面应用程序的WinUI 3中,我有一个要更新的属性,该属性通过x:Bind绑定到该UI。
我希望像在WPF中一样使用Dispatcher进入UI线程,并避免在更新道具时IM遇到的线程错误:
System.Runtime.InteropServices.COMException: 'The application called an interface that was marshalled for a different thread. (0x8001010E (RPC_E_WRONG_THREAD))'
我只是不确定在WinUI3中如何操作,当我尝试时
DispatcherQueue.GetForCurrentThread().TryEnqueue(() => { AeParty.OnSyncHub = false; // Prop bound in ui using x:Bind });
我收到此错误
DispatcherQueue.GetForCurrentThread()为空
我也试过了:
this.DispatcherQueue.TryEnqueue(() => { AeParty.OnSyncHub = false; });
但无法编译:
然后我发现thisGitHub问题,所以我尝试:
SynchronizationContext.Current.Post((o) => { AeParty.OnSyncHub = false; }, null);
这是可行的,但为什么我无法在我的VM中使用调度程序进入UI线程?
推荐答案
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)); } }