++C++; // 未確認飛行 C ブログ

http://ufcpp.net/

WPF の {Binding Path=/}

leave a comment »

昨晩、こんな話が:

コレ クションをバインドした時に何が起きているか

WPFのBindingのPathの解決は結構複雑なことをしております。何のせいでそんなに複雑になるかというと、「マスター詳細シナリオ」とか言う概念のせいだったりします。

マスター詳細シナリオ

以下のページ参照:

DataContextに何かコレクションを与えた上で、選択項目の詳細を見たいという場合があります。こういう状況を指して「マスター詳細シナリオ」と呼んでいるようです。

データ バインディングでは、以下のように、Path=/ と書くことで、「コレクションの選択項目を参照しろ」という意味になります。

<ListBox ItemsSource=”{Binding}” IsSynchronizedWithCurrentItem=”True” />
<ContentControl Content=”{Binding Path=/}” />

この例では、ListBox側で選択された行の要素がContentControlに表示されます。

あるいは、DataContext自信ではなく、その子要素のコレクション(例えばItemsプロパティとしましょう)をバインディングする場合には以下のように書きます。

<ListBox
ItemsSource=”{Binding Items}” IsSynchronizedWithCurrentItem=”True” />
<ContentControl Content=”{Binding Path=Items/}” />

さらに、以下のように、Path=/Name と書くことで、選択項目のNameプロパティを参照できます。

<ListBox ItemsSource=”{Binding}” IsSynchronizedWithCurrentItem=”True” />
<ContentControl Content=”{Binding Path=/Name}” />

Path=/ の省略

さて、ここからが問題。BindingのPathは、実は色々と省略が効きます。Bindingマークアップ拡張が内部で「そっちがダメならこっちをバインディング」みたいな頑張り方を結構しています。例えば、以下のように、/Name から / を取ってみましょう。

<ListBox ItemsSource=”{Binding}” IsSynchronizedWithCurrentItem=”True” />
<ContentControl Content=”{Binding Path=Name}” />

この場合にBindingがどういう挙動をするかというと、

  • DataContextに指定したコレクションがNameプロパティを持っている場合、そのNameプロパティをバインディング。
  • なければ、/Name と同じ挙動をする。すなわち、選択項目のNameプロパティをバインディング。

という判定を内部的に行っているようです。

この挙動に悩まされることはそう多くないとは思いますが、例えば、少々恣意的ですが、以下のようなデータをバインディングに使ってしまうと変なことが起こります。

public class SampleData
{
    public string Name { getset; }
    public int X { getset; }

    // Y は、SampleData にだけ持つ。
    // X 
 Name  SampleList に同名のプロパティを作ってしまう。
    public int Y { getset; }
}

//
こんなことわざわざする人がいるかどうかわからないけども、
//
要素の方と同じプロパティを持つ謎のコレクションを作成。
public class SampleList<T> : List<T>
{
    public string Name { getset; }
    public int X { getset; }
}

Bindingマークアップ拡張は内部で、動的な型(GetType() で得られる型)を見てデータ バインディングしているようなので、IListをDataContextに渡したつもりが、その実体の動的な型はNameプロパティを持っていて…ということも、原理的には起こりえます。

実例

ということで、1つ実例を:

実行結果のスクリーンショットを3枚ほど:

結果を見るに、正直なところ、Path=/ の省略はおすすめできないです。省略した場合には、以下のような挙動を起こします。

  • データ テンプレートの暗黙的な適用(リソース中でDataTemplateにDataType属性を付ける)ができない。
  • コレクション自信と要素に同名のプロパティがあったりなかったりするときの挙動が悩ましい(意図しない挙動になりかねない)。

問題

ドキュメント不足

でも、MSDNのサンプルの多くは、この Path=/ を省略していたりします。そのせいで、/ で「選択項目の参照」ができることを知らない人も多かったりします。

その割に、この辺りの挙動(/ を省略した場合、まずコレクション自信を調べて、なければ選択項目を調べる)に関する説明は自分の知る限り見たことがないんですよね。そりゃ、調べればわかりますけども。

.NET文化に合うのか

XAMLは、どうもHTML+JavaScriptとかXPathとかを意識して作られてるんじゃないかと思っているんですが、「知ってると便利だけども知らないとはまる」って感じの「便利な省略」が多いんですよね。かなりルーズ。

.NET文化的には、もっときっちり書きたいって思う人が多いはず(それが静的な型付けを使う意義なわけで)なので、このルーズさはあまりよくないのではないかと。

広告

Written by ufcpp

2011年1月28日 @ 19:47

カテゴリー: C#

Tagged with ,

コメントを残す

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

WordPress.com ロゴ

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

Twitter 画像

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

Facebook の写真

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

Google+ フォト

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

%s と連携中

%d人のブロガーが「いいね」をつけました。