在 ReactiveUI WPF 中单击启用和禁用按钮

Enable and disable buttons on click in ReactiveUI WPF

在响应式 UI 中,BindCommand 可以将一些控件绑定到视图模型的 属性 或方法,例如ViewModel 中的方法将在单击 XAML 中的某个按钮时执行。

https://www.reactiveui.net/docs/handbook/commands/binding-commands

如何在单击某些按钮时禁用或启用一组按钮

根据文档,BindCommand 应该有第三个参数可以接受一些函数,但找不到示例。

XAML

<Button Content="Start" x:Name="StartButton" />
<Button Content="Stop" x:Name="StopButton" IsEnabled="False" />
<Button Content="Pause" x:Name="PauseButton" IsEnabled="False" />

XAML.cs

// How to enable Stop and Pause when Start was clicked?

this.BindCommand(ViewModel, vm => vm.Stop, view => view.StopButton).DisposeWith(container);
this.BindCommand(ViewModel, vm => vm.Start, view => view.StartButton).DisposeWith(container);
this.BindCommand(ViewModel, vm => vm.Pause, view => view.PauseButton).DisposeWith(container);

// In plain WPF I could do modify controls inside OnClick handler

private void OnStartClick(object sender, RoutedEventArgs e)
{
  // How can I do this in Reactive UI?

  StopButton.IsEnabled = true;
  PauseButton.IsEnabled = true;
}

查看模型

public DashboardViewModel(IScreen screen)
{
  HostScreen = screen;

  // Or how to get access to controls in these event handlers?

  Stop = ReactiveCommand.Create(() => {});
  Start = ReactiveCommand.Create(() => {});
  Pause = ReactiveCommand.Create(() => {});
}

ReactiveCommand.Create 接受一个 IObservable<bool> 来确定 CanExecute 的值是否为:

Start = ReactiveCommand.Create(() => { });
Stop = ReactiveCommand.Create(() => { }, Start.Select(_ => true));
Pause = ReactiveCommand.Create(() => { }, Start.Select(_ => true));

考虑到包括我在内的 3 个人投票赞成在 View Model 中创建相关属性并在 XAML 中绑定它们,我先这样做了。

查看模型

public ReactiveCommand<Unit, Unit> StopCommand { get; protected set; }
public ReactiveCommand<Unit, Unit> StartCommand { get; protected set; }

public bool StopState { get => _stopState; set => this.RaiseAndSetIfChanged(ref _stopState, value); }
public bool StartState { get => _startState; set => this.RaiseAndSetIfChanged(ref _startState, value); }

StopCommand = ReactiveCommand.Create(() =>
{
  StopState = false;
  StartState = true;
});

StartCommand = ReactiveCommand.Create(() =>
{
  StopState = true;
  StartState = false;
});

XAML

<Button Content="Start" IsEnabled="{Binding Path=StartState}" x:Name="StartButton" />
<Button Content="Stop" IsEnabled="{Binding Path=StopState}" x:Name="StopButton" />

这似乎是最 MVVM 的方法,尽管不完全是响应式 UI 方法。然后,我发现这个答案似乎更优雅,不需要 XAML 和视图模型之间的硬编码绑定。

What are the distinctions between the various WhenAny methods in Reactive UI

使用 WhenAnyObservable 我可以订阅选定的命令并从 code-behind 修改 XAML,而无需在视图模型中创建一堆不必要的属性

this
  .BindCommand(ViewModel, vm => vm.StartCommand, view => view.StartButton)
  .WhenAnyObservable(o => o.ViewModel.StartCommand)
  .Subscribe(o =>
  {
    StartButton.IsEnabled = false;
    StopButton.IsEnabled = true;
  })
  .DisposeWith(container);

完成。