要約
ブラウザ上の MVC的な分割を Node Stream API で行うの WPF+Rx+ReactiveProperty 版です
背景
WPFで、真面目にコードビハインドとViewModelを分離して、MVVMを実現するには、INotifyPropertyChangedとICommandの実装が面倒です。
また、個人的に双方向バインディングより、Unidirectional Data Flowが好きです。
作戦
幸い、技術的要素は揃っています。
- イベントをRxで処理
- ViewModelからViewへの変更通知はReactivePropertyで実現
- ViewはXamlで実現
次のような処理の流れを考えます。
- Rxでイベントを受け取る
- Rxストリーム中でイベントを処理
- 結果をReactivePropertyに反映
- Viewを更新
作るアプリケーション
ボタンをクリックしたらカウンターの数値を加算します。
実装
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)すごいです。
良さげ