INotifyPropertyChangedを注入する「Notify Property Weaver」

ネタ元:InfoQ: プロパティへのINotifyPropertyChanged注入することができるIL Weaving

 

昨今のデータバインド中心のUI開発では、INotifyPropertyChangedインターフェイスを実装し、プロパティの変更を通知する仕組みが必須です。

しかし、INotifyPropertyChangedインターフェイスの実装は、普通にやるには愚直にそれぞれのプロパティの変更を自前で判断して実装する必要があり、「面倒だ」というのが定説になりつつあります。

 

INotifyPropertyChanged 実装例
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;

namespace WpfApplication1
{
    public class MainWindowViewModel : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        private string myValue;

        public string MyValue
        {
            get { return myValue; }
            set
            {
                if (myValue != value)
                {
                    myValue = value;

                    OnPropertyChanged("MyValue");
                }
            }
        }

        private string myText;

        public string MyText
        {
            get { return myText; }
            set
            {
                if (myText != value)
                {
                    myText = value;

                    OnPropertyChanged("MyText");
                }
            }
        }

        private void OnPropertyChanged(string propertyName)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

 

この手間を何とかしようと、多くの人たちが試行錯誤を続けてきました。

ある人はT4テンプレートで自動生成し、ある人はヘルパークラスを作成し、またある人はVS拡張のデザイナーを作ったりしています。

 

そんな中、今回登場したのが「Notify Property Weaver」です。

元記事を読むと、ILを書き換えて変更通知してくれるプロパティに変更してくれるツールのようです。さっそく試してみましょう。

 

まず、VS拡張の導入です。これは、元記事にあるリンクからVS Galleryからvsixをダウンロードしてもいいですし、VSの拡張機能マネージャーから検索すればそこからも導入可能です。

 

導入後、先ほどと同じになるように、ViewModelを次のように作成します。ただし、INotifyPropertyChangedは実装しますが、自動実装プロパティを使用します。

 

ViewModel
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;

namespace WpfApplication1
{
    public class MainWindowViewModel : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        public string MyValue { get; set; }
        public string MyText { get; set; }
    }
}

 

次に、[プロジェクト]メニュー→[NotifyPropertyWeaver]→[Configure]を選択します。

image

次のダイアログが表示されるので、そのまま[OK]ボタンをクリックします。

image

これで、プロパティの変更通知が自動で行われるようになります。

(ダイアログのなかではいろいろ設定できるようですが、まだよくわからないので今回はスルーします。)

 

それでは、実際に変更通知機構が働くか試してみましょう。

 

MainWindow.xaml、そしてコードビハインドを次のようにします。

 

MainWindow.xaml
<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation&quot;
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml&quot;
        Title="MainWindow"
        Width="525"
        Height="350">
    <Grid>
        <StackPanel>
            <TextBlock Text="{Binding MyValue}" />
            <TextBlock Text="{Binding MyText}" />
            <Button Name="MyButton" Content="Press!" Click="MyButton_Click" />
        </StackPanel>
    </Grid>
</Window>

 

MainWindow.xaml.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace WpfApplication1
{
    /// <summary>
    /// MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            this.DataContext = new MainWindowViewModel();
            InitializeComponent();
        }

        private void MyButton_Click(object sender, RoutedEventArgs e)
        {
            var vm = this.DataContext as MainWindowViewModel;
            vm.MyValue = "hoge!";
            vm.MyText = "fuga!";
        }
    }
}

 

では実行してみます。まずは、次のようにウィンドウが表示されます。

 

image

 

ここで、[Press!]ボタンをクリックすると、コードビハインドのイベントハンドラーでVMに設定した値が画面に表示されます。

 

image

 

無事、変更通知機構が動いているようです。

 

なお、ビルドして生成されたアセンブリをIL Spyでのぞいてみると、次のようになっていました。

using System;
using System.ComponentModel;
using System.Runtime.CompilerServices;
namespace WpfApplication1
{
    public class MainWindowViewModel : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        public string MyValue
        {
            [CompilerGenerated]
            get
            {
                return this.k__BackingField;
            }
            [CompilerGenerated]
            set
            {
                if (string.Equals(this.k__BackingField, value))
                {
                    return;
                }
                this.k__BackingField = value;
                this.OnPropertyChanged("MyValue");
            }
        }
        public string MyText
        {
            [CompilerGenerated]
            get
            {
                return this.k__BackingField;
            }
            [CompilerGenerated]
            set
            {
                if (string.Equals(this.k__BackingField, value))
                {
                    return;
                }
                this.k__BackingField = value;
                this.OnPropertyChanged("MyText");
            }
        }
        public virtual void OnPropertyChanged(string propertyName)
        {
            PropertyChangedEventHandler propertyChanged = this.PropertyChanged;
            if (propertyChanged != null)
            {
                propertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }
}

確かに、自動的にILに変更通知機構が追加されていることが確認できます。

 

自動でILを書き換えるため、ビルドに少し時間がかかる感じはしますし、自分で変更通知機構をカスタマイズしたいときにどうするか?などの問題はありますが、ViewModel作成の強い味方になってくれそうですね。

広告

INotifyPropertyChangedを注入する「Notify Property Weaver」」への2件のフィードバック

  1. ピンバック: .NET Clips

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト / 変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト / 変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト / 変更 )

Google+ フォト

Google+ アカウントを使ってコメントしています。 ログアウト / 変更 )

%s と連携中