属性类型 在ReactiveUI中,ViewModel中的属性可以根据其用途划分为三种情况:读写属性(Read-Write Properties)、只读属性(Read-Only Properties)和输出属性(Output Properties)。
读写属性 (Read-Write Properties):
读写属性是可以被服务修改,也可以被用户在View中修改的属性。这类属性是我们通常比较熟悉的普通属性。
例如,用户的姓名可能是被服务加载的,而在加载之后又被用户修改。
只读属性 (Read-Only Properties):
只读属性是在构造函数中被初始化且在之后不再变化的属性。
例如, 用户的ID在一般情况下时不允许变化的。
输出属性 (Output Properties):
输出属性是ReactiveUI中新提出的概念,初次接触ReactiveUI时,可能会将输出属性与只读属性混为一谈。尽管输出属性对于用户而言是只读的,但是对于属性本身是可变的。这类属性通常由Observable变化而成,表示属性值可能随时间变化。 例如,用户负债率随用户的总资产和总负债变化,但负债率属性本身是不允许被用户修改的。
在ReactiveUI中,使用这三种属性类型可以更清晰地表示属性的特性和用途。读写属性用于需要双向绑定的数据,只读属性用于一次性初始化后不再改变的数据,而输出属性用于表示可能随时间变化的数据流。这种划分有助于更好地理解和管理ViewModel中的属性。
属性的声明与绑定方法 在明确了属性类型的基础上,ViewModel中所有非集合类型的属性都可以按照下面固定的方式进行声明与绑定。
读写属性的声明需要调用ReactiveObject的RaiseAndSetIfChanged方法,该方法实现了INotifydPropertyChanged。
private string name; public string Name { get => name; set => this.RaiseAndSetIfChanged(ref name, value); } 读写属性的绑定使用TView的Bind方法进行双向绑定。
this.WhenActivated(disposable => { this.Bind(ViewModel, vm => vm.Name, v => v.NameTextBox.Text) .DisposeWith(disposable); }); 只读属性使用一般的声明方式即可。
public int Id {get;} 绑定时,使用单向绑定。
this.WhenActivated(disposable => { this.OneWayBind(ViewModel, vm => vm.Id, v => v.IdTextBlock.Text) .DisposeWith(disposable); }); 输出属性也是使用固定的方式进行声明,但是在初始化时需要注意。
// 声明 private readonly ObservableAsPropertyHelper<double> _debtAssetRatio; public string DebtAssetRatio => _debtAssetRatio.Value; // WhenAnyValue产生一个Observable,当Debt或Asset变化时,会发出新的Debt/Asset的值。这里需要注意Debt和Asset必须也实现了INotifyPropertyChanged,否则无法观察到它们的变化。 // ToProperty将Observable转变为ObservableAsPropertyHelper。 UserAccountViewModel(){ this.WhenAnyValue(x => x.Debt, x => x.Asset, (debt, asset) => debt/asset) .ToProperty(this, x => x.DebtAssetRatio, out _debtAssetRatio); } 由于输出属性对用户而言也是只读的,所以使用单向绑定。
this.WhenActivated(disposable => { this.OneWayBind(ViewModel, vm => vm.DebtAssetRatio, v => v.DebtAssetRatioTextBlock.Text) .DisposeWith(disposable); }); 集合 在使用集合类型的数据,最简单的情况是View中使用的是不可变的数据集合,例如显示Blog中已归档的文章列表,显示用户银行账户的历史交易信息等。这种情况下由于数据只在构造函数中被初始化,所以可以声明为任意集合类型,例如IEnmerable<T>、 IList<T>、ObservableCollection<T>。再在View中使用OneWayBind绑定。
// ViewModel public IEnumerable<Article> Articles {get;} // View this.WhenActivated(disposable => { this.OneWayBind(ViewModel, vm => vm.Articles, v => v.DataGrid.ItemsSource) .DisposeWith(disposable); }); 对于可变数据集合,则需要将集合声明为ObservableCollection<T>,然后在View中使用OneWayBind绑定。要注意的是T也需要实现INotifydPropertyChanged,否则T属性的变化无法触发View更新。
...