==WPF データ==
[[WPF][.Net][Silverlight][Universal Windows Platform][C#]]
{{amazon|4798114200}}
**リソースはリソースバインディングを通じてロード
**コントロールもデータバインディングに大きく依存するコンテンツモデルに基づいている
<<blockquote>>データソースにプロパティをバインドし、依存関係を追跡「、表示を自動的に更新するという概念はWPFのすべての部分に共通<</blockquote>>
===データ変換===
*バインディングが多用されるフレームワークでは、データへのアクセスは、変換可能な場合にのみ可能となる
*名前付きオブジェクトのリストを保持できる共通のプロパティ(Resource)を任意の子要素で使用できる
*参照は階層的に行われ、要素の親に変数が含まれてない場合、その親、次の親へとたどる
<<Window
Text ="Resource"
...>> <<Window.Resource>> <<SolidColorBrush x:Key="toShare">>Yellow<</SolidColorBrush>> <</Window.Resource>> <<Button Background="{StaticResource toShare}">> <</Button>> <</Window>>
=====参照パス=====
*リソースの参照パスは多数の場所からデータを取得できる
|}
<<blockquote>>リソースは、データバインディングの特殊な形式であり、更新頻度が低く数が多いバインディングに最適化されている<</blockquote>>
===バインディングの基本===
**IValueConverter
*FontFamilyの場合、TypeCoverter がFontFamily 型に関連付けられ、これによって変換が自動的に発生する
<<Window ... >> <<StackPanel>> <<TextBox x:Name="textBox1" />> <<ContentControl x:Name="contentControl1"
Content="{Binding ElementName=textBox1, Path=Text}"
FontFamily="{Binding ElementName=textBox2,Path=Text}"/>> <</StackPanel>> <</Window>>
===={x:Bind} マークアップ拡張====
*https://msdn.microsoft.com/ja-jp/library/windows/apps/mt204783.aspx
<<blockquote>>Windows 10 では、{Binding} に代わり、{x:Bind} マークアップ拡張が新たに提供されています。{x:Bind} では、{Binding} の機能のいくつかが省略されていますが、{Binding} よりも短い時間および少ないメモリで動作し、より適切なデバッグをサポートしています。<</blockquote>>
*XAML の読み込み時、{x:Bind} は、バインディング オブジェクトと考えることのできるオブジェクトに変換され、このオブジェクトがデータ ソースのプロパティから値を取得します。
*{x:Bind} と {Binding} によって作成されたバインディング オブジェクトは、ほとんど機能的に同等
*{x:Bind} は、コンパイル時に生成される特定用途のコードを実行し、{Binding} は、汎用的なランタイム オブジェクト検査を実行します
*{x:Bind} バインディング (多くの場合、コンパイル済みバインドと呼ばれます) はパフォーマンスが高く、コンパイル時にバインド式を検証したり、ページの部分クラスとして生成されたコード ファイル内にブレークポイントを設定し、デバッグを行ったりできます
<<blockquote>>これらのファイルは obj フォルダー内にあり、<<view name>>.g.cs (C# の場合) などの名前が付けられています<</blockquote>>
}
*値コンバーターをバインディングに結び付ける
<<ContentContorol
Margin="5"
FontFamily="{Biding ElementName=textBox2,Path=Text}">> <<Content.Control.Content>> <<Binding
ElementName="textBox1"
Path="Text">> <<Binding.Converter>> <<l:HumanConverter xmlns:l="clr-namespace:EssentialWPF"/>> <</Binding.Converter>> <</Binding>> <</Content.Control.Content>> <</ContentControl>>
====データテンプレート====
*データ(DataTypeプロパティによって記述される)を受け取り表示ツリーを構築
*表示ツリー内で、データの各部分にバインドすることができる
*独自の型に対するテンプレートを構築し、データをプロパティにバインド
<<DataTemplate
xmlns:l="clr-namespace:EssentialWPF"
DataType="{x:Type l:Human}">> <<Border Margin="5" Padding="5" BorderBrush="Black" BorderThickness="3" CornerRadius="5">> <<TextBlock Text="{Binding Path=Name}" />> <</Border>> <</DataTemplate>>
*データテンプレートをContentControlに関連付ける方法はさまざま(例えばリソースを通じて)
*ContentTemplateプロパティで設定する例
<<ContentControl
Margin="5"
FontFamily="{Binding ElementName=textBox2,Pat=Text}">> <<ContentControl.Content>> <<Binding .../>> <</ContentControl.Content>> <<ContentControl.ContentTemplate>> <<DataTemplate
xmlns:l="crl-namespace:EssentialWPF"
DataType="{x:Type l:Human}">>
...
<</DataTemplate>> <</ContentControl.ContentTemplate>> <</ContentControl>>
=====WPFでは環境データコンテキストを要素に関連付けることができる=====
*上記例では、バインディングのデータソースが指定されていない
<<TextBloxk Text="{Binding Path=Name}" />>
*データテンプレートの場合、データコンテキストは、テンプレートが変換しているデータに自動的に設定される。
*任意の要素でDataContextプロパティを明示的に設定することが可能
=====TextBoxのTextプロパティを別のTextBoxにバインド=====
<<Window
xmlns="..."
>> <<StackPanel>> <<TextBox Name="text1">>Hello<</TextBox>> <<TextBox Text="{Binding ElementName=text1, Path=Text}" />> <</StackPanel>> <</Window>>
*次の例と同じ
*クラス修飾形式のプロパティ識別子を使用
**リフレクションを使用することによるパフォーマンスへの影響を回避
**添付プロパティへのバインディングが可能になる(TextBoxオブジェクトのGrid.Row プロパティにバインドする場合、{Binding Element Name=text1, Path=(Grid.Row)} のようにする)
<<Window
xmlns="..."
>> <<StackPanel>> <<TextBox Name="text1">>Hello<</TextBox>> <<TextBox Text="{Binding ElementName=text1, Path=(TextBox.Text)}"/>> <</StackPanel>> <</Window>>
====編集====
*値を編集するには、値がいつ変更されたかを知る方法が必要
*規定ではTextBoxはフォーカスを失ったときにデータを更新する(UpdateSourceTriggerプロパティで変更できる)
:
<<TextBlock Text="{Binding Path=Name.Last}"/>> <<TextBlock Text="{Binding Path=Name.First}"/>>
:
<<TextBox Text="{Binding Path=Name.Last}"/>> <<TextBox Text="{Binding Path=Name.First}"/>>
=====リストの場合=====
*リストの場合、単なるプロパティの変更よりも複雑
Add,Remove,Replace,Move,Reset,
}
*もっとも簡単な方法は、INotifyCollectionChangedINotifyCollectionChanged をサポートするObservableCollection<<T>>を使用すること
public class Person : INotifyPropertyChanged {
IList<<Address> > _addresses = new ObservableCollection<<Address>>();
:
}
:
<<StackPanel.Resources>> <<!-- 住所のリストを表示するためのテンプレート -->> <<DataTemplate x:Key="addressTemplate">> <<StackPanel Orientation="Horizontal">> <<TextBlock Text="{Binding Path=Zip}"/>> <<TextBlock Text="{Binding Path=Province}"/>> <<TextBlock Text="{Binding Path=City}"/>> <<TextBlock Text="{Binding Path=Street}"/>> <</StackPanel>> <</DataTemplate>> <</StackPanel.Resources>>
:
<<!--住所のリスト -->> <<ListBox ItemSource="{Binding Path="Addresses}" ItemTemplate="{DynamicResource addresTemplate}" />>
:
===XMLへのバインディング===
====XPathの基本====
*WPFのバインディングは大きくXPathに依存している
<<Media>> <<Book Author="a1" Title="t1"/>> <<Book Author="a2" Title="t2"/>> <<Book Author="a3" Title="t3"/>> <<CD Artist="a4" title="t4"/>> <<DVD Directory="d1" Title="t5">> <<Actor>>A1<</Actor>> <<Actor>>A2<</Actor>> <</DVD>> <</Media>>
*「/」 は最も一般的な演算子で目的の要素へのパスを構築できる(eg:Media/CD)
** Media/Book を選択すると以下が生成される
<<Book Author="a1" Title="t1"/>> <<Book Author="a2" Title="t2"/>> <<Book Author="a3" Title="t3"/>>
*XPathによって、ノードのリストまたは単一のノードが生成されるという考え方はXMLバインディングを学ぶ上で極めて重要
*XMLでは要素の属性の両方がXMLノードとみなされる
*「[]」演算子を使用すると、位置または属性によってノードを選択できる(インデックス1ベース)
** Media/Book[1] を選択すると以下が生成される
<<Book Author="a1" Title="t1"/>>
*属性による選択
** Media/Book/[@Author="t1"]
<<Book Author="a1" Title="t1"/>>
{|class="wikitable"
XmlDocument doc = new XmlDocument();
doc.LoadXml(@"
<<Media xmlns=''>> <<Book Author='a1' Title='t1'/>> <<CD Artist='a1' Title='t2'/>> <<DVD Director='d1' Title='t3'>> <<Actor>>A1<</Actor>> <</DVD>> <</Media>>");
ListBox list = new ListBox();
list.ItemSource = doc.SelectNodes("/Media/Book/@Title");
XmlDocument doc = new XmlDocument();
doc.LoadXml(@"
<<Media xmlns=''>> <<Book Author='a1' Title='t1'/>> <<CD Artist='a1' Title='t2'/>> <<DVD Director='d1' Title='t3'>> <<Actor>>A1<</Actor>> <</DVD>> <</Media>>");
XmlDataProvider dataSource = new XmlDataProvider();
dataSource.Document = doc;
**XMLデータをデータソースに移動するための一般的な方法
**多くの場合、XmlDataProviderを使用せずに、XmlDocument、XmlElementオブジェクトをバインディングソースとして直接使用できる
<<Window :>> <<Window.Resource> > <<XmlDataProvider x:Key="dataSource">> <<x:XData>> <<Media xmlns=''>> <<Book Author='a1' Title='t1'/>> <<CD Artist='a1' Title='t2'/>> <<DVD Director='d1' Title='t3'>> <<Actor>>A1<</Actor>> <</DVD>> <</Media> > <</x:XData>> <</XmlDataProvider>> <</Window.Resource>>
:
<<ListBox ItemSource = "{Binding XPath=/Media/Book/@Title}, Source={StaticResource dataSource}"/>>
=====データソースを動的に判断する=====
*データソースを(動的リソース参照を使用、またはデータソースを判断するためのバインディングを通じて)動的に判断する必要がある場合は、DataContextプロパティを使用できる
<<Window
:
DatraContext="{DynamicResource dataSource}">> <<Window.Resource> > <<XmlDataProvider x:Key="dataSource">> <<x:XData>> <<Media xmlns=''>> <<Book Author='a1' Title='t1'/>> <<CD Artist='a1' Title='t2'/>> <<DVD Director='d1' Title='t3'>> <<Actor>>A1<</Actor>> <</DVD>> <</Media> > <</x:XData>> <</XmlDataProvider>> <</Window.Resource>>
:
<<ListBox ItemSource = "{Binding XPath=/Media/Book/@Title}" /> >
===データテンプレート===
*データテンプレートを使用するとデータの表示方法を定義できる