Giả sử tôi có các mô hình điểm sau:Có mẫu để đăng ký thay đổi thuộc tính phân cấp với UI phản ứng không?
public class AddressViewModel : ReactiveObject
{
private string line;
public string Line
{
get { return this.line; }
set { this.RaiseAndSetIfChanged(x => x.Line, ref this.line, value); }
}
}
public class EmployeeViewModel : ReactiveObject
{
private AddressViewModel address;
public AddressViewModel Address
{
get { return this.address; }
set { this.RaiseAndSetIfChanged(x => x.Address, ref this.address, value); }
}
}
Bây giờ giả sử rằng trong EmployeeViewModel
Tôi muốn để lộ một tài sản với giá trị mới nhất của Address.Line
:
public EmployeeViewModel()
{
this.changes = this.ObservableForProperty(x => x.Address)
.Select(x => x.Value.Line)
.ToProperty(this, x => x.Changes);
}
private readonly ObservableAsPropertyHelper<string> changes;
public string Changes
{
get { return this.changes.Value; }
}
này sẽ chỉ đánh dấu khi một sự thay đổi các tài sản Address
được thực hiện, nhưng không phải khi một sự thay đổi để Line
trong vòng Address
xảy ra. Nếu tôi thay vì làm điều này:
public EmployeeViewModel()
{
this.changes = this.Address.Changed
.Where(x => x.PropertyName == "Line")
.Select(x => this.Address.Line) // x.Value is null here, for some reason, so I use this.Address.Line instead
.ToProperty(this, x => x.Changes);
}
này sẽ chỉ đánh dấu khi một sự thay đổi để Line
trong hiện tại AddressViewModel
xảy ra, nhưng không đưa vào tài khoản thiết lập một mới AddressViewModel
hoàn toàn (và cũng không phù hợp với một null
Address
).
Tôi đang cố gắng giải quyết vấn đề này. Tôi mới đến RxUI vì vậy tôi có thể thiếu một cái gì đó hiển nhiên. Tôi có thể móc thủ công vào các thay đổi địa chỉ và thiết lập đăng ký phụ, nhưng điều này có vẻ xấu và dễ xảy ra lỗi.
Có mẫu hoặc trợ giúp chuẩn nào tôi nên sử dụng để đạt được điều này không?
Dưới đây là một số mã có thể được sao chép/dán này để thử ra:
ViewModels.cs:
namespace RxUITest
{
using System;
using System.Reactive.Linq;
using System.Threading;
using System.Windows.Input;
using ReactiveUI;
using ReactiveUI.Xaml;
public class AddressViewModel : ReactiveObject
{
private string line1;
public string Line1
{
get { return this.line1; }
set { this.RaiseAndSetIfChanged(x => x.Line1, ref this.line1, value); }
}
}
public class EmployeeViewModel : ReactiveObject
{
private readonly ReactiveCommand changeAddressCommand;
private readonly ReactiveCommand changeAddressLineCommand;
private readonly ObservableAsPropertyHelper<string> changes;
private AddressViewModel address;
private int changeCount;
public EmployeeViewModel()
{
this.changeAddressCommand = new ReactiveCommand();
this.changeAddressLineCommand = new ReactiveCommand();
this.changeAddressCommand.Subscribe(x => this.Address = new AddressViewModel() { Line1 = "Line " + Interlocked.Increment(ref this.changeCount) });
this.changeAddressLineCommand.Subscribe(x => this.Address.Line1 = "Line " + Interlocked.Increment(ref this.changeCount));
this.Address = new AddressViewModel() { Line1 = "Default" };
// Address-only changes
this.changes = this.ObservableForProperty(x => x.Address)
.Select(x => x.Value.Line1 + " CHANGE")
.ToProperty(this, x => x.Changes);
// Address.Line1-only changes
//this.changes = this.Address.Changed
// .Where(x => x.PropertyName == "Line1")
// .Select(x => this.Address.Line1 + " CHANGE") // x.Value is null here, for some reason, so I use this.Address.Line1 instead
// .ToProperty(this, x => x.Changes);
}
public ICommand ChangeAddressCommand
{
get { return this.changeAddressCommand; }
}
public ICommand ChangeAddressLineCommand
{
get { return this.changeAddressLineCommand; }
}
public AddressViewModel Address
{
get { return this.address; }
set { this.RaiseAndSetIfChanged(x => x.Address, ref this.address, value); }
}
public string Changes
{
get { return this.changes.Value; }
}
}
}
MainWindow.cs:
using System.Windows;
namespace RxUITest
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.DataContext = new EmployeeViewModel();
}
}
}
MainWindow.xaml:
<Window x:Class="RxUITest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<StackPanel>
<TextBlock Text="{Binding Changes}"/>
<Button Command="{Binding ChangeAddressCommand}">Change Address</Button>
<Button Command="{Binding ChangeAddressLineCommand}">Change Address.Line1</Button>
</StackPanel>
</Window>
Đó là .... rực rỡ! Chỉ cần thử nó và nó đã làm việc. Tôi đã hiểu nhầm toán tử 'WhenAny' khi quan sát bất kỳ thuộc tính" đuôi "nào (' Dòng' trong ví dụ trên). Tôi đã không nhận ra nó cũng có những người thông minh để quan sát bất kỳ tài sản nào trong chuỗi. Cảm ơn Paul. –
là this.RaiseAndSetIfChanged (x => x.Address, ref this.address, value); cú pháp vẫn được hỗ trợ? Tôi chỉ có thể nhận được cú pháp sau đây; this.RaiseAndSetIfChanged (ref this.address, value); – Elangesh
Không, cú pháp cũ không được chấp nhận, bạn chỉ nên sử dụng cú pháp mới ngay bây giờ. –