You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 17:30:52