C#
WPF
MVVM
備忘録
VS2008

[WPF備忘録 - その1] INotifyPropertyChanged [Visual Studio 2008]

はじめに

皆さま方、お久しぶりです。前回の記事を書いてからだいぶ時が過ぎてしまいました。
それもこれもプロパーが無能なおかげで現場が炎上したせいなのは内緒だぞ!

今回は、WPFというよりMVVMアーキテクチャパターンを導入するにあたり、最も基本的かつ最も重要な機能と言っても過言ではない【INotifyPropertyChanged】インターフェースについて記録します。

<< 他の記事へはこちらから >>

INotifyPropertyChanged インターフェースとは?

簡単にいうとプロパティに何らかの変更が加わった際に発生するイベントを定義するためのインターフェースです。
INotifyPropertyChanged自体もすごくシンプルで、eventが1つ定義されているだけのものとなります。

INotifyPropertyChanged.cs
namespace System.ComponentModel
{
    public interface INotifyPropertyChanged
    {
        event PropertyChangedEventHandler PropertyChanged;
    }
}

INotifyPropertyChanged インターフェースの実装

このインターフェースをプロパティ変更を通知したいクラスすべてに実装すれば完成するわけですが、流石にそれだと使いにくためベースとなるクラスをちょちょいと作ります。

NotifyChangedBase.cs
using System.ComponentModel;

namespace Wpf_MVVM_Sample.Model
{
    abstract class NotifyChangedBase : INotifyPropertyChanged
    {
        /// <summary>
        /// プロパティが変更された際に発火するイベントハンドラ.
        /// </summary>
        public event PropertyChangedEventHandler PropertyChanged;

        /// <summary>
        /// プロパティが変更されたことを通知する.
        /// </summary>
        /// <param name="propertyName">プロパティ名</param>
        protected void OnPropertyChanged(string propertyName)
        {
            if (this.PropertyChanged != null)
                this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

あとは、このベースクラスを継承して、プロパティ内でOnPropertyChanged()を呼び出せばOKって寸法です。
このOnPropertyChanged()のメソッド名は他にRaisePropertyChanged()と名付けられることも多いので、お好みで命名してください。

以下、利用例。
Textプロパティを定義し、XAML上のLabelとバインディングさせていきます。

まずは、サクッとViewModelを作っていきましょう。
Textプロパティとコンストラクタのみのシンプルな作りです。Textプロパティは値がnullや前回と同様だった場合は、値の変更と通知を行わないようになっていいます。
ちなみにOnPropertyChanged()メソッドに渡すstringにはプロパティ名をそのまま文字列にして渡しましょう。別な文字列を渡すとView側でデータの変更通知を正しく受け取ることができません。

MainWindowViewModel.cs
using Wpf_MVVM_Sample.Model;

namespace Wpf_MVVM_Sample.ViewModel
{
    class MainWindowViewModel : NotifyChangedBase
    {
        /// <summary>
        /// Label表示用プロパティ
        /// </summary>
        public string Text 
        {
            get { return _text; }
            private set
            {
                if (value != null && value != _text)
                {
                    _text = value;
                    this.OnPropertyChanged("Text");
                }
            }
        }
        private string _text;

        /// <summary>
        /// コンストラクタ
        /// </summary>
        public MainWindowViewModel()
        {
            this.Text = "Sample";
        }
    }
}

バインディングするXAMLはこんな感じです。
ラベルがあるだけ。以上!!
注)Windowのnamespaceを変更した際は、「x:Class="~~~"」の部分の変更をお忘れなく!!

MainWindow.xaml
<Window x:Class="Wpf_MVVM_Sample.View.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:vm="clr-namespace:Wpf_MVVM_Sample.ViewModel"
    Title="MainWindow" Height="300" Width="300">
    <Window.DataContext>
        <vm:MainWindowViewModel/>
    </Window.DataContext>
    <Grid>
        <Label Height ="28"             Margin="12,12,0,0" 
               Content="{Binding Text}" Width ="120"
               VerticalAlignment="Top"  HorizontalAlignment="Left" />
    </Grid>
</Window>

もちろんコードビハインドには何も書いてません。

namespace Wpf_MVVM_Sample.View
{
    /// <summary>
    /// MainWindow.xaml の相互作用ロジック
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }
    }
}

そして、Windowのnamespaceを変更した際に忘れがちなApp.xamlの「StartupUri="~~~"」の部分もきちんと修正しましょうね〜。

App.xaml
<Application x:Class="Wpf_MVVM_Sample.App"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    StartupUri="View/MainWindow.xaml">
    <Application.Resources>

    </Application.Resources>
</Application>

これで一先ずは動きます。
あとは、Textプロパティを変更するようなコードを適当に書いてあげると、連動してLabelのテキストが変更されることを確認できると思います。

次回はICommandインターフェースを実装して、Textプロパティを変更してデータバインディングがきちんと行われていることを確認していきたいと思います。

 あとがき

どこかのタイミングでMVVMについての記事を書きたいと思います(忘れていなければ)。