ReactiveUIとReactivePropertyの簡単な比較

ReactiveUIReactivePropertyを比較してみました。

どちらも深いところまで使ってはいませんが、どちらがスッキリ書けるかの比較のつもりで。

作成するサンプルアプリケーション

初期状態

初期状態

ボタンが押せる状態

ボタンが押せる状態

一番上のテキストボックスに入力すると、すぐに下のテキストが大文字化して逆順に表示されます。
ボタンの文字は最初はHelloとなっていて、もしテキストボックスに2秒以上変化が無ければボタンの文字がテキストボックスの内容と同じになります。また、テキストボックスが10字を超えていればボタンを押せるようになります。
ボタンを押すと、リストボックスに要素が追加されていきます。リストボックスには最初からFirstという要素が入っています。

双方のサンプルが入ったソースコード等はこちらから

ReactiveUI

201409132ReactiveUIは、WPFやUWPの他にも、WinFormsにも対応するなどしています。幅広いプラットフォームとコミュニティの活発さを感じます。
NuGetからはreactiveuiというパッケージを利用してください。すべて小文字なものが本物です。
<Window x:Class="ByReactiveUI.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:ByReactiveUI"
		mc:Ignorable="d"
		Title="MainWindow" Height="350" Width="525">
	<Window.DataContext>
		<local:ReactiveUIViewModel />
	</Window.DataContext>
	<StackPanel>
		<TextBox Text="{Binding Path=Text, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
		<Label Content="{Binding Path=LabelText.Value}" />
		<Button Content="{Binding Path=ButtonText.Value}" Command="{Binding Path=ButtonCommand}" />
		<ListView ItemsSource="{Binding Path=LogList}" />
	</StackPanel>
</Window>

XAMLについては、何の変哲もありません。***.Valueとなっているのも、ViewModelにget-onlyプロパティを作れば***とできます。

	class ReactiveUIViewModel : ReactiveObject
	{
		private string text = "InitValue";
		public string Text
		{
			get
			{
				return text;
			}
			set
			{
				this.RaiseAndSetIfChanged(ref text, value);
			}
		}

		public ObservableAsPropertyHelper<string> LabelText { get; }

		public ObservableAsPropertyHelper<string> ButtonText { get; }

		public ReactiveCommand<object> ButtonCommand { get; }

		public ReactiveList<string> LogList { get; } = new ReactiveList<string> { "First" };

		public ReactiveUIViewModel()
		{
			var textObservable = this.WhenAnyValue(x => x.Text);
			LabelText = new ObservableAsPropertyHelper<string>(textObservable.Select(x => string.Concat(x.ToUpper().Reverse())), x => this.RaisePropertyChanged(nameof(LabelText)), x => { });
			ButtonText = new ObservableAsPropertyHelper<string>(textObservable.Throttle(TimeSpan.FromSeconds(2.0)), x => this.RaisePropertyChanged(nameof(ButtonText)), "Hello");

			ButtonCommand = ReactiveCommand.Create(this.WhenAny(x => x.Text, x => x.Value.Length > 10));
			ButtonCommand.Subscribe(_ => LogList.Add($"Button pressed. @{Text}"));
		}
	}

ViewModelはちょっと複雑で、手動でINotifyPropertyChangedを起こすメソッドを呼ばなければなりません。また、ObservableAsPropertyHelper<T>#Valueはget-onlyプロパティなので、Textプロパティはこのような形でなければなりません。

ReactiveProperty

201409133ReactivePropertyはWPFやUWPの等のXAMLを使うプラットフォームに対応しています。UniRxを開発された方をはじめ、日本のC#界隈で活躍されている方々によって作られています。
NuGetからはReactivePropertyというパッケージを利用してください。
<Window x:Class="ByReactiveProperty.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:ByReactiveProperty"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">
	<Window.DataContext>
		<local:ReactivePropertyViewModel />
	</Window.DataContext>
	<StackPanel>
		<TextBox Text="{Binding Path=Text.Value, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
		<Label Content="{Binding Path=LabelText.Value}" />
		<Button Content="{Binding Path=ButtonText.Value}" Command="{Binding Path=ButtonCommand}" />
		<ListView ItemsSource="{Binding Path=LogList}" />
	</StackPanel>
</Window>

XAMLについては、こちらも何の変哲もありません。ただし、TwoWayでバインドした要素でも***.Valueとなっています。

	class ReactivePropertyViewModel
	{
		public ReactiveProperty<string> Text { get; } = new ReactiveProperty<string>("InitValue");

		public ReactiveProperty<string> LabelText { get; }

		public ReactiveProperty<string> ButtonText { get; }

		public ReactiveCommand ButtonCommand { get; }

		public ReactiveCollection<string> LogList { get; } = new ReactiveCollection<string> { "First" };

		public ReactivePropertyViewModel()
		{
			LabelText = Text.Select(x => string.Concat(x.ToUpper().Reverse())).ToReactiveProperty();
			ButtonText = Text.Throttle(TimeSpan.FromSeconds(2.0)).ToReactiveProperty("Hello");

			ButtonCommand = Text.Select(x => x.Length > 10).ToReactiveCommand();
			ButtonCommand.Subscribe(_ => LogList.Add($"Button pressed. @{Text.Value}"));
		}
	}

こちらのViewModelはすっきりしています。ReactiveProperty<T>#Valueはget-setプロパティなので、ReactiveUIのようにsetterでイベント処理を行う必要はありません。
しかし、逆にsetterを使って複雑なことをしたい場合は、よくあるINotifyPropertyChangedを実装してイベントを発行する必要があるので面倒かもしれません。

まとめ

ReactiveUI
途中から導入する場合でもXAMLの変化が少なくできそう。WinFormsにも対応。
ReactiveProperty
ViewModelがきれいに直感的に書ける。疑問が出てきても日本語で質問できる環境。

C# 6になったことでget-onlyプロパティがとても簡単に書けるようになり、これらのライブラリの使いやすさも向上しています。
MVVMフレームワークと合わせてガンガン使っていきましょう。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です