为WinUI3/Uno Platform扩展UI线程安全BindableBase的方案是否合理?
关于BindableBase线程安全修改的疑问
背景与修改实现
我目前使用MSDN《深入数据绑定》推荐的问答游戏示例中的BindableBase实现。由于需要从后台线程更新属性,且不想每次都用DispatcherQueue.TryEnqueue包裹写入操作,我对BindableBase做了如下修改:
public abstract class BindableBase : INotifyPropertyChanged { // 在对象创建时一次性缓存同步上下文 private static SynchronizationContext _SynchronizationContext = SynchronizationContext.Current; /* ...原版本中未修改的代码... */ protected void OnPropertyChanged([CallerMemberName] string propertyName = null) { // 在UI线程的同步上下文上通知所有委托 _SynchronizationContext.Post(d => { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); }, null); } }
该方案目前运行符合预期,但存在一个明显限制:所有派生对象必须在UI线程创建,这对我来说并无问题。不过我并非线程技术专家,想知道该方案是否会引发意外问题;另外,我是在了解DispatcherQueue之前编写的此代码,是否应该用DispatcherQueue替代SynchronizationContext来触发PropertyChanged委托?
补充说明
我这么做的目的是让对象自身确保始终在UI线程触发PropertyChanged委托,而非由对象的调用者处理。现在我可以编写如下代码:
绑定对象
public class BindableObject : BindableBase { private int _SomeValue = 0; public int SomeValue { get => _SomeValue; set => SetProperty(ref _SomeValue, value); } }
XAML代码
<TextBlock Text="{x:Bind MyObject.SomeValue, Mode=OneWay}"/>
页面代码
public sealed partial class MyPage : Page { public BindableObject MyObject { get; init; } = new(); private async void Button_Click(object sender, RoutedEventArgs args) { await Task.Run(async () => { // 这里执行一些耗时操作 MyObject.SomeValue = 1; // 不需要调用DispatcherQueue // 没有抛出异常,且x:Bind能正确更新UI }); } }
内容的提问来源于stack exchange,提问作者Setsu
相关产品推荐
相关产品推荐

