WPFで便利な機能としてバインド(binding)があります。
自作のユーザーコントロールでバインドしようと思っても、普通のプロパティを定義するだけだとバインドしてくれません。
実は、開存関係プロパティという特別なプロパティを定義する必要があります。
ただ、定義の方法は若干面倒ではあるものの、あるパターンに沿ってコードを記述するだけでバインド対応が可能です。
今回は、ユーザーコントロールでバインドに対応するための依存関係プロパティの記述方法について解説したいと思います。
依存関係プロパティとは
依存関係プロパティと普通のプロパティでは何が違うのでしょうか?
まず、普通のプロパティは、クラスの外から値を代入したり参照するためのものであり、例えば文字列型の ProductName というプロパティを作成する場合、次の様に記述します。
1 |
public string ProductName {get;set;} |
単純に内部の変数を外部に公開しているだけであり、プロパティに値をセットする場合は、値をセットするコードを自分で記述しなければなりません。
つまり、外部にある何らかの変数の値が変わったからといって、バインドのように自動的にプロパティの値が書き変わることはないのです。
これに対して、依存関係プロパティは、外部にある何らかの変数の値が変わることによって、自動的にプロパティの値が書き変わります。
逆に言うと、そのように振る舞うための特別なプロパティの定義の仕方(ルール)があって、そう記述することによってバインド対応が出来るようになります。
バインドの仕組みはコールバックイベント
では、WPFにおけるバインドとはどの様な仕組みなのでしょう。
バインドを行ったプロパティにおいて、バインド元の変数の値が変化した時、イベントが発行されます。
つまり、バインドという行為を行うという事は、バインド元に対して「値が変化したら、このイベントを発行してね」と依頼しているのです。
一般的に、相手に対して自分を呼び出してもらう行為を「コールバック」と呼びますが、バインド元が「コールバックのイベント」を発行してくれることで、バインド先が変化を検知し、変化後の値を表示することができるのです。
逆に言うと、依存関係プロパティに記述する内容としては、コールバックイベントを用意して、その中にバインド元の値が変化した時の動作(例えばバインド元の値をテキストボックスに代入するなど)を記述する必要があるという事です。
依存関係プロパティの記述ルール
まず、一番大きなルールとしては、下記の通り3つの記述が必要になる点です。
1つ目は依存関係プロパティをWPFに登録するための記述、もう1つは外部からアクセスするためのプロパティ、最後にコールバックイベントです。
依存関係プロパティ、コールバックイベントは、バインドの仕組みの中で使われるものであり、外部のクラスから直接アクセスされたり、呼び出されることは有りません。
外部からは、あくまでもプロパティ名を通してアクセスされます。
つまり、依存関係プロパティが外部から隠蔽されているということになります。
プロパティ、依存関係プロパティ、コールバックイベントとバインドの関係を簡単に図式化しました。
おおよそ、以下の様に理解してもらえれば、実際のコードが理解しやすくなると思います。
2つ目のルールとしては、依存関係プロパティ名やコールバックイベント名に、プロパティの名前を入れるというルールです。
異なる名前にすると可読性が悪くなるので、このルールは徹底しておきましょう。
下記が依存関係プロパティの標準的なコードです。
ユーザーコントロール名、プロパティ名、コールバックイベントの中身以外は、同じ記述が使いまわしできます。
依存関係プロパティの記述方法
下記は、ProductCode というプロパティをバインド対応にするためのソースコードです。
このままコピペして、プロパティ名、ユーザーコントロール名だけ変えて、コールバックイベントの中身を適切に記述してもらえれば使えると思います。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
//依存関係プロパティ public static readonly DependencyProperty ProductCodeProperty = DependencyProperty.Register("ProductCode", typeof(string), typeof(CellUserControl), new FrameworkPropertyMetadata("ProductCode", new PropertyChangedCallback(OnProductCodeChanged))); //外部に公開するプロパティ public string ProductCode { get { return (string)GetValue(ProductCodeProperty); } set { SetValue(ProductCodeProperty, value); } } //コールバックイベントの処理 private static void OnProductCodeChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e) { var control = (CellUserControl)obj; control.uxProductCode.Text = (obj != null) ? control.ProductCode : control.uxProductCode.Text; } |
まとめ
今回はユーザーコントロールのプロパティをバインドに対応する方法として、依存関係プロパティの記述方法について解説しました。
なぜ依存関係プロパティと呼ぶかは、ソースコードを見て分かると思いますが、通常のプロパティとは違って、あちこちに関係している=依存していますよね。
だから依存関係プロパティと呼ばれています。
依存関係プロパティはもっと奥が深いのですが、バインドしたいというだけであれば、記述量は多くなりますが、ワンパターンを記述していくだけなので難易度は高くないと思います。
この記事が皆さんの参考になれば幸いです。