DependencyObjectってのがある。
WPFのコントロール達は、親へ親へだどっていくと、DependencyObjectへたどり着く。
たとえばWindowだと…
Window → ContentControl → Control → FrameworkElement → UIElement → Visual → DependencyObject
といった感じ。
このクラスを継承すると、依存プロパティや添付プロパティといったものが作れるようになる。
依存プロパティとかは、バインディングなんかもできるようになるという優れもの。
早速作ってみようと思う。
DependencyObjectを継承してPersonクラスをこさえる。
依存プロパティの作り方は至って簡単。DependencyProperty型のstatic readonlyな変数があればOK。
public class Person : DependencyObject
{
public static readonly DependencyProperty NameProperty = .....
}
DependencyPropertyのインスタンスは、DependencyProperty.Registerメソッドで作成する。
public class Person : DependencyObject
{
public static readonly DependencyProperty NameProperty =
DependencyProperty.Register("Name", typeof(string), typeof(Person));
}
第一引数でプロパティ名、第二引数で型、第三引数でオーナの型を渡す。
今はNameという名前のstring型のプロパティをPersonクラスに追加するので上記のような感じになる。
クラスができたので早速使ってみよう。
名前に適当な値をセットしたPersonクラスを作って、Nameをセットして表示してみる。
var p = new Person();
// 値の設定
p.SetValue(Person.NameProperty, "かずき");
// 値の取得
Console.WriteLine(p.GetValue(Person.NameProperty));
実行結果は、"かずき"と表示されるだけ。
これで何が嬉しいの?っていうのをちょっと見てみよう。
using System;
using System.Windows;
using System.Windows.Data;
namespace DependencyObjectSample
{
class Program
{
static void Main(string[] args)
{
// Personを二人用意して
var p1 = new Person();
var p2 = new Person();
Binding binding = new Binding();
// Nameプロパティを
binding.Path = new PropertyPath(Person.NameProperty);
// プロパティが変わったタイミングで
binding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
// 双方向に伝達します
binding.Mode = BindingMode.TwoWay;
// バインディングのソースはp1
binding.Source = p1;
// バインドのターゲットはp2
BindingOperations.SetBinding(p2, Person.NameProperty, binding);
// p1の名前を変更すると
p1.SetValue(Person.NameProperty, "かずき");
// p2の名前も変更される
Console.WriteLine(p2.GetValue(Person.NameProperty));
// p2の名前を変更すると
p2.SetValue(Person.NameProperty, "一希");
// p1の名前も変更される
Console.WriteLine(p1.GetValue(Person.NameProperty));
}
}
}
実行結果
かずき
一希
上のプログラムは、p1とp2のNameプロパティを双方向に同期をとるようにバインドしている。
DependencyPropertyを使うとデータのバインドが簡単にできる!!
因みに、今まで書いたコードみたいに毎回SetValueやGetValueでDependencyPropertyを使うのは非常にめんどくさいので普通は下のようにCLRのプロパティも一緒に定義する。
public class Person : DependencyObject
{
public static readonly DependencyProperty NameProperty =
DependencyProperty.Register("Name", typeof(string), typeof(Person));
public string Name
{
get { return (string)GetValue(NameProperty); }
set { SetValue(NameProperty, value); }
}
}
こうしておくと、さっきのバインディングのプログラムは見やすくなる。
using System;
using System.Windows;
using System.Windows.Data;
namespace DependencyObjectSample
{
class Program
{
static void Main(string[] args)
{
// Personを二人用意して
var p1 = new Person();
var p2 = new Person();
Binding binding = new Binding();
// Nameプロパティを
binding.Path = new PropertyPath(Person.NameProperty);
// プロパティが変わったタイミングで
binding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
// 双方向に伝達します
binding.Mode = BindingMode.TwoWay;
// バインディングのソースはp1
binding.Source = p1;
// バインドのターゲットはp2
BindingOperations.SetBinding(p2, Person.NameProperty, binding);
// p1の名前を変更すると
p1.Name = "かずき";
// p2の名前も変更される
Console.WriteLine(p2.Name);
// p2の名前を変更すると
p2.Name = "一希";
// p1の名前も変更される
Console.WriteLine(p1.Name);
}
}
}