WPFのReactiveCommandを使いTextBoxの文字が入力されている場合、有効なボタンのサンプルコード

コンピュータ

コマンドの有効・無効の切り替えは、
ReactiveProperty>bool< から ToReactiveCommand() を使用して作成する方法があります。

ただ、この方法だと ViewModel 内に bool 型のフラグが増えてしまいます。

そこで今回は、プロパティの変化を条件式として利用することで、
コマンドの有効・無効を切り替える方法を試してみたいと思います。


ViewModel


    // プロパティ
    public ReactivePropertySlim<string> TextBox1 { get; private set; }
         = new("");

    // コマンド
    public ReactiveCommandSlim Button1Command { get; }
    // コンストラクタ
    public MainWindowViewModel()
    {
        // 
        TextBox1
            .Skip(1)
            .Subscribe(value =>
            {
                Debug.Print($"タイトルの値が{value}に変更された");
            })
            .AddTo(Disposable);

        Button1Command = TextBox1
            .Select(x => x != "")
            .ToReactiveCommandSlim()
            .WithSubscribe(()=>
            {
                Debug.Print("Button1 Click");
            })
            .AddTo(Disposable);
    }
Button1Command = TextBox1
.Select(x => x != "")

TextBox1の変更で、文字列が空でないこと条件にしている。


XAML

    <Window.DataContext>
        <local:MainWindowViewModel/>
    </Window.DataContext>
    <Grid>
        <StackPanel>
            <TextBox Text="{Binding TextBox1.Value, UpdateSourceTrigger=PropertyChanged}" />
            <Button Content="Button1" Command="{Binding Button1Command}" />
        </StackPanel>
    </Grid>

</Window>

サンプルコードでは
TextBoxとButtonだけで、Buttonが無効状態だと、
フォーカスの移動先が無いので、変更通知が行われない。

しかたが無いので、UpdateSourceTrigger=PropertyChangedをセットすることで、
1文字入力ごととに変更通知が行われるようにしています。


実行

初期はボタンが押せない


TextBoxに1文字でも入力があると、
ボタンが有効化

TextBoxの文字列が空になると
ボタンは無効化される。


ViewModelでUIの状態を IsXXX のようなプロパティとして定義するのは、
XAMLでバインドする場合や、他の処理から参照する必要がある場合に限られます。

それ以外の場合、IsXXX をプロパティとして用意しても、
単なるフラグのON/OFFを保持するだけになってしまいます。
そのため、ViewModelのプロパティとして公開する意味はあまりありません。

ReactivePropertyでは、必要な場面で無名の ReactiveProperty>bool< を生成することができます。
名前を持たないため、ViewModelのプロパティとして定義する必要がなく、余計なフラグを増やさずに済みます。
また、特別な意味を持つ状態として扱う必要もありません。

初めは、この連動の仕組みが少し面倒に感じました。
バインド(イベント)の管理に加えて、コマンドの状態も別途管理する必要があるからです。

しかし逆に考えると、バインディングはかなり大まかな仕組みです。
実際には「このタイミングではバインドしてほしくない」と感じる場面にも、しばしば遭遇します。

そのため、バインディングだけに頼るのではなく、
条件式を利用してUIの状態を制御する方法も有効だと思います。

ただ、感覚的にはイベントドリブンでプログラミングしているのと、それほど大きくは変わらないように感じます。
どちらの場合でも、適切なタイミングを管理する必要があります。

早すぎたり、遅すぎたりと、ちょうど良いタイミングを探す作業になる点は同じです。

Rxでは、そのタイミングを条件式として表現できますが、
その条件を成立させるための環境を整える必要がある点は、イベントドリブンと似ている部分だと感じました。

コメント