LoginSignup
14
17

More than 5 years have passed since last update.

RxとReactivePropertyを使って、WPFでUnidirection Data Flowを実現する

Posted at

要約

ブラウザ上の MVC的な分割を Node Stream API で行うの WPF+Rx+ReactiveProperty 版です

背景

WPFで、真面目にコードビハインドとViewModelを分離して、MVVMを実現するには、INotifyPropertyChangedとICommandの実装が面倒です。
また、個人的に双方向バインディングより、Unidirectional Data Flowが好きです。

作戦

幸い、技術的要素は揃っています。

  • イベントをRxで処理
  • ViewModelからViewへの変更通知はReactivePropertyで実現
  • ViewはXamlで実現

次のような処理の流れを考えます。

  1. Rxでイベントを受け取る
  2. Rxストリーム中でイベントを処理
  3. 結果をReactivePropertyに反映
  4. Viewを更新

作るアプリケーション

ボタンをクリックしたらカウンターの数値を加算します。

out.gif

実装

View

TextBlockにカウンターの値をバインドします。

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApplication1"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">
    <StackPanel>
        <Button x:Name="button" Content="Button"  />
        <TextBlock x:Name="textBlock" Text="{Binding Count.Value}"/>
    </StackPanel>
</Window>

コードビハインド

using Reactive.Bindings;
using System;
using System.Reactive.Linq;
using System.Windows;

namespace WpfApplication1
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();

            // DataContextにViewModelをバインド
            var vm = new ViewModel();
            DataContext = vm;

            // イベントに処理をバインド
            Observable.FromEvent<RoutedEventHandler, RoutedEventArgs>(
                    h => (s, e) => h(e),
                    h => button.Click += h,
                    h => button.Click -= h
                )
                .Subscribe(_ =>
                {
                    // ViewModelを更新
                    vm.Count.Value++;
                });
        }
    }

    public class ViewModel
    {
        public ReactiveProperty<int> Count { get; } = new ReactiveProperty<int>();
    }
}
  • DataContextにReactivePropertyを使ったViewModelを設定して、変更通知をバインド
  • RxのObservable.FromEventを使って、ボタンクリックイベントに処理をバインド

感想

ModelとContorllerは分離されていません。
ですが、Subscribe内の処理をServiceクラスに分離すればなんとでもなりそうです。

JavaScriptより簡単に実装できました、WPF(とRxとReactiveProperty)すごいです。
良さげ:sushi:

参考

14
17
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
14
17