WPF MVVM异步开发:如何用NotifyTask实现双向绑定?
WPF异步数据加载:NotifyTask结合双向绑定的优化方案探讨
我正在学习WPF应用中的异步数据加载,参考了Stephen Cleary的相关内容,其中介绍了AsyncEx库的NotifyTask类(原名NotifyTaskCompletion)——可以在构造函数中启动任务,通过绑定它的状态属性(如IsCompleted、IsFaulted等)来展示加载、错误状态。
实际使用中发现,NotifyTask.Result只有计算型getter,不会触发PropertyChanged,因此仅支持WPF的OneWay绑定,而原示例只绑定了天生OneWay的Label.Content。
我需要找到既能利用NotifyTask的状态管理能力,又支持TwoWay绑定的实现方式,目前想到两种思路,但都觉得架构冗余,想请教更优方案:
方案1:NotifyTask单独管理状态,拆分双向绑定属性
XAML代码
<TextBox Text="{Binding Text}"> <TextBox.Style> <Style TargetType="TextBox" BasedOn="{StaticResource {x:Type TextBox}}"> <Setter Property="IsEnabled" Value="True" /> <Style.Triggers> <DataTrigger Binding="{Binding LoadTextTask.IsNotCompleted}" Value="True"> <Setter Property="IsEnabled" Value="False" /> </DataTrigger> </Style.Triggers> </Style> </TextBox.Style> </TextBox>
C#代码
internal class Example_Method1 : ViewModelBase { internal Example_Method1() { LoadTextTask = new NotifyTask<string?>(LoadText(), null); } public NotifyTask<string?> LoadTextTask { get; private set; } private string? _text; internal string? Text { get => _text; set => SetField(ref _text, value); // SetField负责触发PropertyChanged } private async Task<string?> LoadText() { return await DAL.ReallyHeavyLoadingOperation(); } }
方案1的问题
- 构造函数中无法await任务,必须通过
NotifyTask的完成事件将结果同步到Text属性,每个异步加载属性都要对应两个属性和事件处理,架构冗余; - 如果用单个
NotifyTask加载多组数据,需要DTO或元组,仍要解决任务完成后的同步触发问题。
方案2:用实现INotifyPropertyChanged的泛型类包装NotifyTask返回值
C#代码
internal class Notifiable<TResult> : INotifyPropertyChanged { public Notifiable(TResult? value) { _value = value; } private TResult? _value; internal TResult? Value { get => _value; set { if (!EqualityComparer<TResult>.Default.Equals(_value, value)) { _value = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Value))); } } } public event PropertyChangedEventHandler? PropertyChanged; } internal class Example_Method2 : ViewModelBase { internal Example_Method2() { Text = new NotifyTask<Notifiable<string?>>(LoadText(), null); } internal NotifyTask<Notifiable<string?>> Text { get; private set; } private async Task<Notifiable<string?>> LoadText() { return new Notifiable<string?>(await DAL.ReallyHeavyLoadingOperation()); } }
XAML代码
<TextBox Text="{Binding Text.Result.Value}"> <TextBox.Style> <Style TargetType="TextBox" BasedOn="{StaticResource {x:Type TextBox}}"> <Setter Property="IsEnabled" Value="True" /> <Style.Triggers> <DataTrigger Binding="{Binding Text.IsNotCompleted}" Value="True"> <Setter Property="IsEnabled" Value="False" /> </DataTrigger> </Style.Triggers> </Style> </TextBox.Style> </TextBox>
方案2的问题
- 虽然支持TwoWay绑定,合并了状态与数据属性,但架构仍显冗余;
- 无法自定义单个属性的setter逻辑(比如强制转大写);
- 尝试将
Notifiable的功能整合到NotifyTask中,但因NotifyTask.Result是计算型getter,实现复杂度较高。
恳请各位提供更优的NotifyTask结合TwoWay绑定的实现方案。
内容的提问来源于stack exchange,提问作者Chronicide
相关产品推荐
相关产品推荐

