Uno Platform Cat API示例Windows端Dispatcher为空问题求助
Uno Platform中Dispatcher为空的问题修复
我正在实现Uno Platform的Cat API示例,在以下代码中遇到Dispatcher为空的问题:WASM版本运行正常,但Windows版本无法工作。试过相关解决方案,仅生效一次后Dispatcher再次为空。
using System; using System.Collections.Generic; using System.ComponentModel; using System.Runtime.CompilerServices; using System.Threading.Tasks; using Microsoft.UI.Dispatching; namespace TheCatApiClient.Models.ViewModels { public abstract class DispatchedBindableBase : INotifyPropertyChanged { // Insert variables below here protected DispatcherQueue Dispatcher => DispatcherQueue.GetForCurrentThread(); // Insert variables below here public event PropertyChangedEventHandler? PropertyChanged; // Insert SetProperty below here protected virtual bool SetProperty<T>(ref T backingVariable, T value, [CallerMemberName] string? propertyName = null) { if (EqualityComparer<T>.Default.Equals(backingVariable, value)) return false; backingVariable = value; RaisePropertyChanged(propertyName); return true; } // Insert RaisePropertyChanged below here protected void RaisePropertyChanged([CallerMemberName] string? propertyName = null) { #pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed DispatchAsync(() => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName))); #pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed } // Insert DispatchAsync below here protected async Task DispatchAsync(DispatcherQueueHandler callback) { var hasThreadAccess = #if __WASM__ true; #else Dispatcher.HasThreadAccess; #endif if (hasThreadAccess) { callback.Invoke(); } else { var completion = new TaskCompletionSource(); Dispatcher.TryEnqueue(() => { callback(); completion.SetResult(); }); await completion.Task; } } } }
问题原因
当前代码中Dispatcher属性每次访问都会调用DispatcherQueue.GetForCurrentThread(),如果ViewModel在非UI线程初始化,或者后续在非UI线程访问该属性,都会返回null;之前的临时解决方案只覆盖了单次场景,无法解决后续的线程访问问题。
修复方案
1. 缓存Dispatcher到私有字段(推荐)
在ViewModel构造时获取并缓存UI线程的Dispatcher,避免每次访问都重新获取:
using System; using System.Collections.Generic; using System.ComponentModel; using System.Runtime.CompilerServices; using System.Threading.Tasks; using Microsoft.UI.Dispatching; namespace TheCatApiClient.Models.ViewModels { public abstract class DispatchedBindableBase : INotifyPropertyChanged { private readonly DispatcherQueue _dispatcher; protected DispatcherQueue Dispatcher => _dispatcher; public event PropertyChangedEventHandler? PropertyChanged; protected DispatchedBindableBase() { // 确保ViewModel在UI线程初始化,否则抛出异常提示 _dispatcher = DispatcherQueue.GetForCurrentThread() ?? throw new InvalidOperationException("ViewModel必须在UI线程实例化"); } protected virtual bool SetProperty<T>(ref T backingVariable, T value, [CallerMemberName] string? propertyName = null) { if (EqualityComparer<T>.Default.Equals(backingVariable, value)) return false; backingVariable = value; RaisePropertyChanged(propertyName); return true; } protected void RaisePropertyChanged([CallerMemberName] string? propertyName = null) { // 忽略异步警告,无需等待分发完成 _ = DispatchAsync(() => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName))); } protected async Task DispatchAsync(DispatcherQueueHandler callback) { var hasThreadAccess = #if __WASM__ true; #else _dispatcher.HasThreadAccess; #endif if (hasThreadAccess) { callback.Invoke(); } else { var completion = new TaskCompletionSource(); _dispatcher.TryEnqueue(() => { callback(); completion.SetResult(); }); await completion.Task; } } } }
2. 确保ViewModel在UI线程实例化
在页面的构造函数或Loaded事件中初始化ViewModel,保证操作在UI线程执行:
public MainPage() { this.InitializeComponent(); // 此处为UI线程,初始化ViewModel DataContext = new YourCatViewModel(); }
3. 备选:手动传入Dispatcher(适合非UI线程初始化场景)
如果必须在后台线程创建ViewModel,可以从UI线程提前获取Dispatcher并传入ViewModel构造函数:
// 页面中(UI线程) var uiDispatcher = DispatcherQueue.GetForCurrentThread(); DataContext = new YourCatViewModel(uiDispatcher); // ViewModel构造函数修改 protected DispatchedBindableBase(DispatcherQueue dispatcher) { _dispatcher = dispatcher ?? throw new ArgumentNullException(nameof(dispatcher)); }
内容的提问来源于stack exchange,提问作者Ace
相关产品推荐
相关产品推荐

