LoginSignup
131
144

More than 3 years have passed since last update.

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

Last updated at Posted at 2015-10-20

期待

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を使う点に注意が必要です。
はじめて試した時、見事にはまりました。

リンク

131
144
1

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
131
144