Edited at

INotifyPropertyChanged実装のありえない面倒くささと、ReactivePropertyの信じられない素晴らしさ

More than 3 years have passed since last update.


期待

MVVMや双方向バインディングでは、バインドしたViewModelの更新を画面に反映して欲しいです。

ViewModelにINotifyPropertyChangedインターフェイスを実装して実現するようです。


INotifyPropertyChangedを実装する方法

方法 : INotifyPropertyChanged インターフェイスを実装するに、従って実装します。


ViewModel.cs

using System;

using System.ComponentModel;
using System.Runtime.CompilerServices;

namespace WpfApplication1
{
public class ViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}

private string message = "";
public string Message
{
get
{
return this.message;
}
set
{
if (value != this.message)
{
this.message = value;
NotifyPropertyChanged();
}
}
}
}
}


次のようの気持ちでいっぱいです。


  • PropertyChangedEventHandlerとNotifyPropertyChangedのおまじない感

  • 自動実装プロパティーで、プロパティーを簡潔に書けるC#の魅力とはなんだったのか?

  • (必要な場合)さらにModelとの変換ロジックも実装するの?

  • こんなことで「ViewModelを書けば、(ビューの)データと描画ロジックを美しく分離できる」と言えるのか?


MainWindow.xaml.cs

using System.Windows;

namespace WpfApplication1
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
var vm = new ViewModel();

DataContext = vm; // DataContextにViewModelをバインド
vm.Message = "Hello"; // DataContextのプロパティーを更新すると画面に反映
}
}
}



MainWindow.xaml

<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">
<Grid>
<TextBlock Text="{Binding Message}"/>
</Grid>
</Window>

こちらは期待通りです。


スクリーンショット

実行すると、こんな感じです。

スクリーンショット 2015-10-20 22.34.20.png


軽減手段

いくつか多少軽減する方法はあるようです。

データクラスとして非本質的な記述が、あまり減らないのが気になります。


ReactivePropertyを使うと


ViewModel.cs

using Reactive.Bindings;

namespace WpfApplication1
{
public class ViewModel
{
public ReactiveProperty<string> Message { get; } = new ReactiveProperty<string>();
}
}


この簡潔さ。データクラスがプロパティー定義だけを持つ、圧倒的な簡潔さです。

型名は少し長いですが、VisualStudioの補完機能を考えれば気になりません。


MainWindow.xaml.cs

using System.Windows;

namespace WpfApplication1
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
var vm = new ViewModel();

DataContext = vm; // DataContextにViewModelをバインド
vm.Message.Value = "Hello"; // DataContextのプロパティーを更新すると画面に反映
}
}
}



MainWindow.xaml

<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">
<Grid>
<TextBlock Text="{Binding Message.Value}"/>
</Grid>
</Window>

値の参照・設定にValueを使う点に注意が必要です。

はじめて試した時、見事にはまりました。


リンク