WPFでReactivePropertyを導入するとRelayCommandを書かなくてよくなる

コンピュータ

ReactivePropertyを導入すると、オブザーバーベースのプログラミングが可能になります。

従来のWPFのプログラミングでは、イベントをきっかけに処理を行う
イベントドリブン型(データバインディングも含む)の設計が基本になります。

一方、ReactivePropertyでは

「どのタイミングで誰がデータを書き換えたか」

ではなく、

「データが変更された」という事実

に注目して処理を組み立てます。

これは従来のイベント中心の設計とは異なる、
オブザーバーベースのプログラミングパラダイムと言えるでしょう。


このようにReactivePropertyは、導入する価値が非常に高い仕組みですが、
WPFで利用する場合には、さらにいくつかのメリットがあります。

まず、データバインディング用のプロパティを実装する際に必要となる
ボイラープレートコードを大幅に省略することができます。

また、コマンドをバインディングするために通常は ICommand を実装する必要がありますが、
ReactivePropertyでは ReactiveCommand を使用することで、
この部分も簡潔に記述することが出来ます。

そのため、ViewModelのコード量を減らすことができ、
全体的にコーディングが楽になります。


従来型のMVVM

RelayCommand.cs(ICommandの実装)

using System;
using System.Windows.Input;

public class RelayCommand : ICommand
{
    private readonly Action _execute;

    public RelayCommand(Action execute)
    {
        _execute = execute;
    }

    public event EventHandler? CanExecuteChanged;

    public bool CanExecute(object? parameter) => true;

    public void Execute(object? parameter)
    {
        _execute();
    }
}

ViewModel

using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Windows;
using System.Windows.Input;

public class MainWindowViewModel : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler? PropertyChanged;

    private string _name = "";

    public string Name
    {
        get => _name;
        set
        {
            _name = value;
            OnPropertyChanged();
        }
    }

    public ICommand ShowCommand { get; }

    public MainWindowViewModel()
    {
        ShowCommand = new RelayCommand(Show);
    }

    private void Show()
    {
        MessageBox.Show(Name);
    }

    void OnPropertyChanged([CallerMemberName] string? name = null)
    {
        PropertyChanged?.Invoke(this,
            new PropertyChangedEventArgs(name));
    }
}

XAML(UI)

<StackPanel Margin="20">

    <TextBox Width="200"
             Text="{Binding Name,
             UpdateSourceTrigger=PropertyChanged}"/>

    <Button Content="表示"
            Command="{Binding ShowCommand}"
            Width="100"/>

</StackPanel>

ReactiveProperty版
ReactivePropertyを使うとかなり短くなります。

ViewModel

using Reactive.Bindings;
using System.Windows;

public class MainWindowViewModel
{
    public ReactivePropertySlim<string> Name { get; }
        = new("");

    public ReactiveCommandSlim ShowCommand { get; }

    public MainWindowViewModel()
    {
        ShowCommand = new ReactiveCommandSlim();

        ShowCommand.Subscribe(_ =>
        {
            MessageBox.Show(Name.Value);
        });
    }
}

省略していますが、INotifyPropertyChangedとIDisposableを実装した方がよいです。


XAML

<StackPanel Margin="20">

    <TextBox Width="200"
             Text="{Binding Name.Value,
             UpdateSourceTrigger=PropertyChanged}"/>

    <Button Content="表示"
            Command="{Binding ShowCommand}"
            Width="100"/>

</StackPanel>

RelayCommandが綺麗に消えて、
プロパティのボイラープレートも

private string _name = "";

public string Name
{
    get => _name;
    set
    {
        _name = value;
        OnPropertyChanged();
    }
}

から

public ReactivePropertySlim Name { get; }
    = new("");

へと、大分すっきりした形になりました。

WPFでプログラムを書く場合、データバインディングのための
プロパティを大量に定義することになります。

そのため、このようにシンプルなコードで実装できる点は非常にありがたいところです

コメント