[RxUI] 3.5 – Windows Presentation Foundation(WPF)
手动实现IViewFor<T>
,并确保ViewModel是DependencyProperty
。另外,应始终通过WhenActivated取消绑定,否则会导致内存泄漏。如果不使用WhenActivated
,那么XAML的DependencyProperty
系统会导致内存泄漏。有几条规则需要注意,最重要的一条是:如果对除此之外的其它任何操作执行WhenAny
,则需要将其放在WhenActivated
中。有关详细信息,请参见WhenActivated。
本示例中的目标是将ViewModel的TheText
属性双向绑定到TextBox,并将TheText
属性单向绑定到TextBlock,因此当用户在TextBox中键入文本时,TextBlock就会更新。
public class TheViewModel : ReactiveObject
{
private string theText;
public string TheText
{
get => theText;
set => this.RaiseAndSetIfChanged(ref this.theText, value);
}
public ReactiveCommand<Unit,Unit> TheTextCommand { get; }
public TheViewModel()
{
TheTextCommand = ReactiveCommand
.CreateFromObservable(ExecuteTextCommand);
}
private IObservable<Unit> ExecuteTextCommand()
{
TheText = "Hello ReactiveUI";
return Observable.Return(Unit.Default);
}
}
<Window /* snip */>
<StackPanel>
<TextBox x:Name="TheTextBox" />
<TextBlock x:Name="TheTextBlock" />
<Button x:Name="TheTextButton" />
</StackPanel>
</Window>
在此示例中,将手动实现IViewFor<TViewModel>
接口,但对于UserControl
,应该使用封装了IViewFor
实现的ReactiveUserControl
。
public partial class TheView : Window, IViewFor<TheViewModel>
{
public static readonly DependencyProperty ViewModelProperty = DependencyProperty
.Register(nameof(ViewModel), typeof(TheViewModel), typeof(TheView));
public TheView()
{
InitializeComponent();
ViewModel = new TheViewModel();
// Setup the bindings
// Note: We have to use WhenActivated here, since we need to dispose the
// bindings on XAML-based platforms, or else the bindings leak memory.
this.WhenActivated(disposable =>
{
this.Bind(this.ViewModel, x => x.TheText, x => x.TheTextBox.Text)
.DisposeWith(disposable);
this.OneWayBind(this.ViewModel, x => x.TheText, x => x.TheTextBlock.Text)
.DisposeWith(disposable);
this.BindCommand(ViewModel, x => x.TheTextCommand, x => x.TheTextButton)
.DisposeWith(disposable);
});
}
public TheViewModel ViewModel
{
get => (TheViewModel)GetValue(ViewModelProperty);
set => SetValue(ViewModelProperty, value);
}
object IViewFor.ViewModel
{
get => ViewModel;
set => ViewModel = (TheViewModel)value;
}
}