[C#][Windows ストア アプリ][WPF] INotifyPropertyChanged の実装に便利なクラスとコードスニペット

WPF や Silverlight、Windows 8 や Windows RT の Windows ストア アプリでは、UI の記述に XAML を使うことが多い。

そして、データバインドするために INotifyPropertyChanged をしょっちゅう実装することになる。

これが結構面倒なので、開発者は普通、少しでも楽になるような工夫をしている。

そのような「有り勝ちな工夫」について。

■ 工夫する前のコード

「工夫」する前のコードは、こんな感じだ。

using System.ComponentModel;
class MyViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
int id = 0;
public int Id
{
get { return id; }
set {
if (value != id) {
id = value;
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs("Id"));
}
}
}
string name = string.Empty;
public string Name
{
get { return name; }
set {
if (value != name) {
name = value;
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs("Name"));
}
}
}
}

プロパティ毎の記述が、結構煩雑だ。

上記ではプロパティが2つしかないが、プロパティが多くなれば、この繰り返しはそれに比例して増えることになる。

■ ヘルパー クラス

Expression や Caller Info を使ったヘルパー クラスを用意するともう少し記述が楽になる。

※ 参考:

こんな感じのヘルパー クラスだ。

using System;
using System.ComponentModel;
using System.Linq.Expressions;
using System.Runtime.CompilerServices;
public static class PropertyChangedEventHandlerExtensions
{
// Caller Info を使っているので C# 5.0 以降
public static void Raise(this PropertyChangedEventHandler onPropertyChanged, object sender, [CallerMemberName] string propertyName = "")
{
if (onPropertyChanged != null)
onPropertyChanged(sender, new PropertyChangedEventArgs(propertyName));
}
public static void Raise<PropertyType>(this PropertyChangedEventHandler onPropertyChanged, object sender, Expression<Func<PropertyType>> propertyExpression)
{ onPropertyChanged.Raise(sender, propertyExpression.GetMemberName()); }
static string GetMemberName<MemberType>(this Expression<Func<MemberType>> expression)
{ return ((MemberExpression)expression.Body).Member.Name; }
}

これを使うことで、先のコードは「少しだけ」簡潔になる。また、プロパティ名の変更に対して安全になった。

using System.ComponentModel;
class MyViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
int id = 0;
public int Id
{
get { return id; }
set {
if (value != id) {
id = value;
PropertyChanged.Raise(this);
}
}
}
string name = string.Empty;
public string Name
{
get { return name; }
set {
if (value != name) {
name = value;
PropertyChanged.Raise(this);
}
}
}
}

■ コード スニペット

更に Visual Studio でコード スニペットを利用することで、タイピングの手間を減らすことができる。

このコード スニペットは、例えば次のような XML だ。

<?xml version="1.0" encoding="utf-8" ?>
<CodeSnippets xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
<CodeSnippet Format="1.0.0">
<Header>
<Title>Property for INotifyPropertyChanged</Title>
<Shortcut>propin</Shortcut>
<Description>Code snippet for property for INotifyPropertyChanged.
Use this class (for C# 5.0 or later):
using System.ComponentModel;
using System.Runtime.CompilerServices;
public static class PropertyChangedEventHandlerExtensions
{
public static void Raise(this PropertyChangedEventHandler onPropertyChanged, object sender, [CallerMemberName] string propertyName = "")
{
if (onPropertyChanged != null)
onPropertyChanged(sender, new PropertyChangedEventArgs(propertyName));
}
}</Description>
<Author></Author>
<SnippetTypes>
<SnippetType>Expansion</SnippetType>
</SnippetTypes>
</Header>
<Snippet>
<Declarations>
<Literal>
<ID>type</ID>
<ToolTip>type name</ToolTip>
<Default>int</Default>
</Literal>
<Literal>
<ID>field</ID>
<ToolTip>field name</ToolTip>
<Default>myField</Default>
</Literal>
<Literal>
<ID>property</ID>
<ToolTip>property name</ToolTip>
<Default>MyProperty</Default>
</Literal>
</Declarations>
<Code Language="csharp"><![CDATA[ $type$ $field$ = default($type$);
public $type$ $property$
{
get { return $field$; }
set {
if (!value.Equals($field$)) {
$field$ = value;
PropertyChanged.Raise(this);
}
}
}
$end$]]></Code>
</Snippet>
</CodeSnippet>
</CodeSnippets>

これを、"propin.snippet" のような名前で、テキスト ファイルとして任意の場所に保存する。

次に、Visual Studio で、メニューから 「ツール」 – 「コード スニペット マネージャー」を開く。

コード スニペット マネージャー
コード スニペット マネージャー

「インポート」ボタンを押す。先ほどのテキスト ファイル “propin.snippet” を選択する。

コード スニペットのインポート
コード スニペットのインポート

"My Code Snippets" にチェックをいれて、「完了」ボタンを押す。

これでコード スニペットが使えるようになる。

例えば、先程の MyViewModel クラスの Name プロパティの下にカーソルを合わせて、propin とタイプして[TAB]キーを2回押してみよう。

新しいプロパティが簡単に挿入でき、型名、フィールド名、プロパティ名が楽に設定できるだろう。

コード スニペットによるプロパティの追加
コード スニペットによるプロパティの追加