「[[マイクロソフト系技術情報 Wiki>http://techinfoofmicrosofttech.osscons.jp/]]」は、「[[Open棟梁Project>https://github.com/OpenTouryoProject/]]」,「[[OSSコンソーシアム .NET開発基盤部会>https://www.osscons.jp/dotNetDevelopmentInfrastructure/]]」によって運営されています。 -[[戻る>XAML]] * 目次 [#i78ae0d5] #contents *概要 [#d37660b8] 基本的なXAMLの書き方。 *名前空間 [#x46c4d22] XAMLにおける各種の名前空間の宣言は、xmlns属性を使用したXML名前空間にて行う。~ ここでは、以下の既定の名前空間の宣言を例にとって説明する。 -名前空間の宣言 <Window x:Class="WpfApplication1.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" -XML名前空間の簡単な説明~ http://www.kanzaki.com/docs/sw/names.html **WPF名前空間 [#u9e59dba] 2行目のXML名前空間の宣言(xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation")では、~ WPFフレームワーク(PresentationFramework.dll)のアセンブリ内に同梱されるURIにマップされた~ CLR名前空間(System.Windows.Controls、System.Windows.Dataなど)を、既定のXML名前空間(プレフィックスなし)として割り当てている。~ そのため、既定でXAMLからWPFフレームワークのCLRオブジェクトを利用できる。 **XAML名前空間 [#f7e47ba4] 3行目のXML名前空間の宣言(xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml")では、~ URIにマップされた共通的なXAMLの言語機能がXML名前空間(x)として割り当てられている。~ これにより、「x:」というプレフィックスを使用することで、「[[言語機能>#n6cf5f58]]」で説明する、XAMLの言語機能を使用できるようになる。 **CLR名前空間 [#b9a3d659] CLR名前空間について以下を例にとって説明する。 ***(1) [#j611ebcc] -CLR名前空間の宣言 <Window x:Class="WpfApplication1.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:igDP="http://infragistics.com/DataPresenter" <--- 名前空間の宣言(追加 Title="Window1" Height="300" Width="300"> <Grid> <igDP:XamDataGrid Name="xamDataGrid1"/> <--- 名前空間の使用例 </Grid> </Window> Infragistics社製のNetAdvantageなど、XmlnsDefinitionアセンブリ属性でURIとCLR名前空間のマップが指定されたサードパーティ製のUIコンポーネントをD&DでVSデザイナから追加した場合、上記の例のように自動的にXML名前空間の宣言が追加される。 -MSDN > .NET Frameworkクラス ライブラリ > System.Windows.Markup.XmlAttributeProperties.XmlnsDefinitionプロパティ~ http://msdn.microsoft.com/ja-jp/library/system.windows.markup.xmlattributeproperties.xmlnsdefinition.aspx なお、XML名前空間には一意の名前を自由に付与でき(上記の例ではigDP)、このプレフィックスを使用することで、XAMLからUIコンポーネントのCLRオブジェクトを利用できる。 ***(2) [#y81abbb2] この他に、URIとしてCLR名前空間とアセンブリを直接指定する方法もある。 -CLR名前空間の宣言 xmlns:sys="clr-namespace:(CLR名前空間);assembly=(アセンブリ名)" --例1:サードパーティ製品 <Window x:Class="WpfApplication1.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:igDP="clr-namespace:Infragistics.Windows.DataPresenter;assembly=Infragistics3・・・" <--- 名前空間の宣言 Title="Window1" Height="300" Width="300"> <Grid> <igDP:XamDataGrid Name="xamDataGrid1"/> <--- 名前空間の使用例 --例2:.NET Framework <Window x:Class="WpfApplication1.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:sys="clr-namespace:System;assembly=mscorlib" <--- 名前空間の宣言 Title="Window1" Height="300" Width="300"> <Window.Resources> <x:Array x:Key="List" Type="{x:Type sys:String}"> <--- 名前空間の使用例 --例3:自作の同一プロジェクトのクラス <Window x:Class="WpfApplication1.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:uc="clr-namespace:WpfApplication1" <--- 名前空間の宣言 Title="Window1" Height="300" Width="300"> <StackPanel Orientation="Vertical"> <uc:UserControl1 x:Name="userControl1"/> <--- 名前空間の使用例 -この方法では、「clr-namespace」、「assembly」などの定義済みトークンを使用する。 --当該プロジェクト中のCLR名前空間を指定する場合は、「assembly」トークンは省略できる。 --XML名前空間には一意の名前を自由に付与でき、このプレフィックスを使用することで、XAMLからUIコンポーネントのCLRオブジェクトを利用できる。 -製品並みのカスタムのUIコントロールを開発・使用するなどの目的を除いて、CLRクラスを開発しXAMLから使用する場合、 --一般的には「clr-namespace、assembly」の定義済みトークンを使用する。 --ただし、この方法は、1つのCLR名前空間に対して、1つのXML名前空間しか割り当てられない --(XmlnsDefinitionアセンブリ属性を使用すると、1つのXML名前空間に複数のCLR名前空間を割り当てられる)。 ***参考 [#v51c1b09] -MSDN > WPFの基礎 > WPFのXAML > XAML名前空間およびWPF XAMLの名前空間の割り当て~ http://msdn.microsoft.com/ja-jp/library/ms747086.aspx *言語機能 [#ad009a58] XAMLの言語機能である -「[[ディレクティブ>#cd4daa01]]」 -「[[マークアップ拡張>#hc49ac25]]」 について説明する。 -MSDN > .NET Framework XAMLサービスの概念説明のドキュメント > XAML名前空間 (x:) 言語機能~ http://msdn.microsoft.com/ja-jp/library/ms753327.aspx **ディレクティブ [#j78f478c] XAMLの言語機能が提供する各種ディレクティブについて説明する。 |項番|ディレクティブ|説明|h |~|~|例|h |1|x:Class|XAML上から分離クラス(コードビハインド)のクラス名を定義する。| |~|~|<Window x:Class="WpfApplication1.Window1"| |2|x:Subclass|パーシャル クラスをサポートしない言語で使用する。通常は利用しない。| |~|~|-| |3|x: ClassModifier|クラスのアクセスレベルを変更する。通常は利用しない。| |~|~|-| |4|x:Code|XAML上にインラインコードを実装する場合に使用する。通常は利用しない。| |~|~|<Grid>&br; <x:Code>&br; <![CDATA[&br; void button1_Click(object sender, RoutedEventArgs e) {&br; button1.Content = "Hello World";&br; }&br; ]]>&br; </x:Code>&br; <Button Name="button1" Click="button1_Click">Button</Button>&br;</Grid>| |5|x:FieldModifier|プロパティのアクセスレベルを変更する。通常は利用しない。| |~|~|-| |6|x:Key|XAMLで定義された各種「リソース」を識別する。下記は、x:Keyを使用して「スタイル」の「リソース」をボタンに「データ バインディング」する例。| |~|~|<Window.Resources>&br; <Style x:Key="buttonStyle" TargetType="{x:Type Button}">&br; <Setter Property="Background" Value="LightYellow" />&br; </Style>&br;</Window.Resources>&br;<Grid>&br; <Button Style="{StaticResource buttonStyle}">Hello Style</Button>&br;</Grid>| |7|x:Name|XAMLで生成したCLRオブジェクトに名前を付与する。Name属性と差異は無い。| |~|~|<Button x:Name="button1">&br; Click Here&br;</Button>| |8|x:Shared|静的なリソースを、取得の度に生成する場合に使用する。通常は利用しない。&br;※ true : 静的(全てのインスタンスは同じ)&br; false : 動的(取得の度に生成する)&br; 既定値 : true| |~|~|-| |9|x:TypeArguments|ジェネリックの型引数をコンストラクタに渡す。&br;(.NET Framework 4.0のXAML 2009からのサポート)| |~|~|<!-- XAML 2009 -->&br;<ObservableCollection x:TypeArguments="Employee">&br; <l:Employee FirstName="John" Name="Doe" />&br; <l:Employee FirstName="Tim" Name="Smith" />&br;</ObservableCollection>| |10|x:Uid|ローカライゼーションのプロセスとツールによって使用される一意識別子を指定する 。| |~|~|-| |11|xml:lang|カルチャ情報を宣言する。| |~|~|<Window x:Class="WpfApplication1.Window1"&br; xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"&br; xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"&br; xml:lang="ja-JP"| -MSDN > Windows Presentation Foundation > グローバライズとローカライズ > WPFのグローバリゼーション~ http://msdn.microsoft.com/ja-jp/library/ms745650.aspx **マークアップ拡張 [#b565ab69] XAMLの言語機能が提供する各種「マークアップ拡張」について説明する。~ 通常、「マークアップ拡張」は、「{」と「}」の2つの中括弧を使用することでXAMLパーサに対し、拡張されたプロパティ指定方法を指示する。 -MSDN > WPFの基礎 > WPFのXAML > マークアップ拡張機能とWPF XAML~ http://msdn.microsoft.com/ja-jp/library/ms747254.aspx ***XAMLで定義されたマークアップ拡張 [#ld42b6a9] 以下、XAMLの機能である「XAMLで定義されたマークアップ拡張」を一覧する。~ これらの種類は、中括弧+「x:」プレフィックスの直後の文字列トークンによって識別される。 -XAMLに実装されたマークアップ拡張 |項番|文字列トークン|説明|h |~|~|例|h |1|x:Static|静的プロパティ(定数、静的プロパティ、フィールド、列挙値)を参照する。&br;構文:<object property="{x:Static Member=prefix:typeName.staticMemberName}" .../>| |~|~|<Button &br; Foreground="{x:Static Member=SystemColors.InfoTextBrush}"&br; Background="{x:Static Member=SystemColors.InfoBrush}">&br; Click Here&br;</Button>| |2|x:Null|CLRオブジェクトのプロパティにnull値を設定する(既定値をnullクリアする場合など)。| |~|~|<Button x:Name="button1" Background="{x:Null}" Click="button1_Click">&br; Click Here&br;</Button>| |3|x:Type|CLRクラスの型情報を指定する。| |~|~|詳しくは、下記、項番4の例を参照のこと。| |4|x:Array|IEnumerableを持つArrayオブジェクト(配列)を生成する。| |~|~|<Window.Resources>&br; <x:Array x:Key="List"&br; Type="{x:Type sys:String}">&br; <sys:String>A</sys:String>&br; <sys:String>B</sys:String>&br; <sys:String>C</sys:String>&br; </x:Array>&br;</Window.Resources>&br;<StackPanel>&br; <ListBox ItemsSource="{Binding Source={StaticResource List}}"/>&br;</StackPanel>&br;&br;※ 先頭で、.NET FrameworkのSystem名前空間のインポートが必要&br; xmlns:sys="clr-namespace:System;assembly=mscorlib"&br;&br;※ StaticResourceについては次項で説明する。| ※ x:Arrayは、例外的に中括弧と共に使用しない。 ***WPF固有のマークアップ拡張 [#dbf77234] 以下、WPF の機能である「WPF固有のマークアップ拡張」を一覧する。~ こちらは、プロパティ値に「データ バインディング」や、「リソース」への参照を指定できる。 -XAMLに実装されたマークアップ拡張 |項番|文字列トークン|説明|h |~|~|構文 ※ 「[[プロパティ属性構文>#q550d6b3]]」と「[[プロパティ要素構文>#fa957fd3]]」については、後述する。|h |1|{Binding&br;・・・|Bindingオブジェクトに「バインディング ターゲット」のプロパティを設定することで、「データ バインディング」を実装する。&br;MSDN > WPFの基礎 > WPFのXAML > WPF XAML拡張機能 > バインディングのマークアップ拡張機能&br;http://msdn.microsoft.com/ja-jp/library/ms750413.aspx| |~|~|具体例は、「[[データ バインディングの基礎>#bbd76ce0]]」を参照のこと。| |2|{StaticResource&br;・・・|既に定義されたリソースに対する参照を検索し、任意のXAMLプロパティ属性の値を設定する。| |~|~|具体例は、「[[リソースとのデータ バインディング>#ac5a7f33]]」を参照のこと。&br;&br;プロパティ属性構文:&br;<object property="{StaticResource key}" .../>&br;&br;なお、「データ バインディング」で使用する場合は、次のようになる。&br;<object property="{Binding Source={StaticResource key} ...}" .../>&br;&br;プロパティ要素構文:&br;<object>&br; <object.property>&br; <StaticResource ResourceKey="key" .../>&br; </object.property>&br;</object>| |3|{DynamicResource&br;・・・|リソースが変化したときに、任意のXAMLプロパティ属性の値を設定する。&br;keyには、x:Key属性によって指定された既存の「リソース」に対応するキーを指定する。| |~|~|具体例は、「[[リソースとのデータ バインディング>#ac5a7f33]]」を参照のこと。&br;&br;プロパティ属性構文:&br;<object property="{DynamicResource key}" .../>&br;&br;なお、「データ バインディング」で使用する場合は、次のようになる。&br;<object property="{Binding Source={DynamicResource key} ...} " .../>&br;&br;プロパティ要素構文:&br;<object>&br; <object.property>&br; <DynamicResource ResourceKey="key" .../>&br; </object.property>&br;</object>| |4|{RelativeSource&br;・・・|Binding.RelativeSourceを指定する。詳しくは、下記のURLを参照のこと。&br;また、次ページで例を挙げて説明する。&br;&br;MSDN > WPFの基礎 > WPFのXAML > WPF XAML拡張機能 > RelativeSourceのマークアップ拡張機能&br;http://msdn.microsoft.com/ja-jp/library/ms743599.aspx| |~|~|具体例は、次ページを参照のこと。&br;&br;プロパティ属性構文:&br;<Binding RelativeSource="{RelativeSource modeEnumValue}" .../>&br;&br;なお、「データ バインディング」で使用する場合は、次のようになる。&br;<object property="{Binding RelativeSource={RelativeSource modeEnumValue} ...}" .../>&br;&br;プロパティ要素構文:&br;<Binding>&br; <Binding.RelativeSource>&br; <RelativeSource Mode="modeEnumValue"/>&br; </Binding.RelativeSource>&br;</Binding>&br; OR &br;<Binding>&br; <Binding.RelativeSource>&br; <Relative&br; Mode="FindAncestor"&br; AncestorType="{x:Type typeName}"&br; AncestorLevel="intLevel"/>&br; </Binding.RelativeSource>&br;</Binding>| |5|{TemplateBinding&br;・・・|親コントロールに適用したプロパティ値を「テンプレート」に反映させる。&br;MSDN > WPFの基礎 > WPFのXAML > WPF XAML拡張機能 > TemplateBindingのマークアップ拡張機能&br;http://msdn.microsoft.com/ja-jp/library/ms742882.aspx| |~|~|具体例は、「[[テンプレート>#bb58b780]]」を参照のこと。&br;&br;プロパティ属性構文:&br;<object property="{TemplateBinding TargetProperty }" .../>| |6|{ThemeDictionary&br;・・・|カスタム コントロールの作成者やサードパーティ製のUIコンポーネントの、&br;コントロールの「スタイル」をアプリケーションの「リソース」から読み込む。&br;&br;MSDN > WPFの基礎 > WPFのXAML > WPF XAML拡張機能 > ThemeDictionaryのマークアップ拡張機能&br;http://msdn.microsoft.com/ja-jp/library/ms752067.aspx| |~|~|-| ※ keyには、x:Keyディレクティブによって指定された既存のリソースに対応するキーを指定する。 ***RelativeSourceの例 [#b35e6e76] 以下、RelativeSourceの「マークアップ拡張」について、XAMLサンプルを用いて説明する。~ なお、Button.Template以下の要素(→ 「[[テンプレート>#bb58b780]]」)については、「[[テンプレート>#bb58b780]]」を参照のこと。 -RelativeSourceの例 <StackPanel> <TextBlock Text="{Binding RelativeSource ={RelativeSource Self}, Path=FontFamily}" />・・・(1) <Border Background="Black" Height="5"/> <TextBlock Text="{Binding RelativeSource ={RelativeSource AncestorType={x:Type StackPanel}},Path=Orientation}" />・・・(2) <Border Background="Black" Height="5"/> <Button Content="Hello world"> <Button.Template> <ControlTemplate TargetType="{x:Type Button}"> <ContentPresenter Content="{Binding RelativeSource ={RelativeSource TemplatedParent}, Path=Content}" />・・・(3) </ControlTemplate> </Button.Template> </Button> </StackPanel> -レンダリング結果 #ref(RenderingResult.png,left,nowrap,レンダリング結果) -(1) では、TextBlock要素自身のFontFamilyプロパティを取得して、自身のTextプロパティに設定している。 -(2) では、親要素(AncestorType 属性に指定されているStackPanel型)を検索し、Orientationプロパティを取得して、自身のTextプロパティに設定している。 -(3) では、TemplatedParent 属性により、テンプレートを適用しているControlTemplate(ここでは、ControlTemplateであるButton要素)の~ Contentプロパティを取得し、ContentPresenterクラスのContentプロパティに設定している。 -MSDN > WPFの基礎 > WPFのXAML > WPF XAML拡張機能~ http://msdn.microsoft.com/ja-jp/library/ms747180.aspx *プロパティの設定方法 [#ra4d77a1] プロパティの設定方法として、 -プロパティ属性構文:~ 要素の属性にテキストを使用して設定する。 -プロパティ要素構文:~ 要素のinnerText・innerXMLを使用してプロパティを設定する。 の2つの構文について説明する。 以下、TextBox要素に対して、同等の属性を設定する~ 「[[プロパティ属性構文>#q550d6b3]]」と「[[プロパティ要素構文>#fa957fd3]]」の例を示す。 **プロパティ属性構文 [#tb0bd2e6] 要素の属性にテキストを使用してプロパティを設定する方法 -プロパティ属性構文の例 <TextBox Width = "100" FontSize = "30" Text = "text1" Background = "White" Foreground = "Blue" /> **プロパティ要素構文 [#s389a559] 要素のinnerText・innerXMLを使用してプロパティを設定する方法 -プロパティ要素構文の例 <TextBox> <TextBox.Width>100</TextBox.Width> <TextBox.FontSize>30</TextBox.FontSize> <TextBox.Background> <SolidColorBrush Color="White"/> </TextBox.Background> <TextBox.Foreground> <SolidColorBrush Color="Blue"/> </TextBox.Foreground> <TextBox.Text>text1</TextBox.Text> </TextBox> なお、子要素のコレクションを設定する「[[プロパティ要素構文>#fa957fd3]]」である -Panel.Childrenプロパティ -ItemsControl.Itemsプロパティ などは、暗黙的に使用されるため明記が不要のものもある。 **型コンバータ [#r36d6abd] XAMLパーサは、XAMLの「[[プロパティ属性構文>#q550d6b3]]」として指定された各属性テキストを、~ プリミティブ型に変換できるリテラル文字列として解釈するか、「型コンバータ」を使用してオブジェクトに変換する。 なお、「型コンバータ」(と、そのベース クラスであるTypeConverterクラス)は、~ .NETのコンポーネントとコントロールのデザイン時・実行時の動作を実装する一般的なクラスであり、WPF独自のクラスではない。~ しかし、XAMLの「[[プロパティ属性構文>#q550d6b3]]」からのCLRプロパティ設定を多用するWPF / Silverlight開発では、その存在を認識しておいたほうが良い。 XAMLパーサは通常、プロパティの型(CLRクラス)にTypeConverterAttribute属性 が付与されているかを調べる。~ 付与されている場合は、この属性値に基づいた「型コンバータ」を使って、TypeConverter.ConvertFromメソッド により文字列をプロパティ値に変換する。 以下は、ユーザ コントロールに、MyPointというカスタムの型を取るCLRプロパティを実装しXAMLに公開、~ XAMLの「[[プロパティ属性構文>#q550d6b3]]」として指定された各属性テキストを、カスタムの型に変換する「型コンバータ」を実装した例である。 ***カスタム型 [#p2ae99f0] MyPointというカスタム型(型コンバータを実装) /// <summary> /// カスタム型(型コンバータを実装) /// </summary> [TypeConverter(typeof(MyPointConverter))] public class MyPoint { public MyPoint(int x, int y) { this._x = x; this._y = y; } private int _x; public int X { set { this._x =value; } get { return this._x; } } private int _y; public int Y { set { this._y = value; } get { return this._y; } } } ***型コンバータ [#k0c10e95] /// <summary>カスタム型の型コンバータ</summary> public class MyPointConverter : TypeConverter { /// <summary>CanConvertFrom(変換可能かチェックする)</summary> public override bool CanConvertFrom( ITypeDescriptorContext context, Type sourceType) { if (sourceType == typeof(string)) { return true; } return base.CanConvertFrom(context, sourceType); } /// <summary>指定された文字列をカスタム型(MyPoint)に変換する</summary> public override object ConvertFrom( ITypeDescriptorContext context, CultureInfo culture, object value) { if (value is string) { string[] v = ((string)value).Split(new char[] { ',' }); return new MyPoint(int.Parse(v[0]), int.Parse(v[1])); } return base.ConvertFrom(context, culture, value); } /// <summary>指定されたカスタム型(MyPoint)を文字列に変換する</summary> public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) { if (destinationType == typeof(string)) { return ((MyPoint)value).X + "," + ((MyPoint)value).Y; } return base.ConvertTo(context, culture, value, destinationType); } } ***ユーザ コントロール [#gc3459c6] MyPointというカスタム型のCLRプロパティを実装 /// <summary> /// UserControl1.xaml の相互作用ロジック /// </summary> public partial class UserControl1 : UserControl { // CLRプロパティの定義(XAML属性に公開可能) private MyPoint _myLocation; public MyPoint MyLocation { set { this._myLocation = value; } get { return this._myLocation; } } ・・・ ***型コンバータの使用例 [#gc5dd259] 上記のユーザ コントロールのカスタムの型を取るCLRプロパティを、以下のようにXAMLの「[[プロパティ属性構文>#q550d6b3]]」として指定された各属性テキストから初期化できる。 <uc:UserControl1 x:Name="userControl1" MyLocation="10,20"/> ただし、(当然ながら、)文字列からの変換をサポートしているだけで、すべてのプロパティ値をサポートすることはできない。~ 文字列で表現できないプロパティ値は、「[[プロパティ属性構文>#q550d6b3]]」ではなく「[[プロパティ要素構文>#fa957fd3]]」として記述する方法を取る。 -MSDN > WPFの基礎 > WPFのXAML > TypeConverters及びXAML~ http://msdn.microsoft.com/ja-jp/library/aa970913.aspx *コンテンツ構文 [#m4c088a5] 「コンテンツ構文」とは、Contentプロパティ(またはItemsコレクション プロパティ)に要素を設定する構文である。~ ContentPropertyAttributeを付けることで、通常、属性に指定されるContentプロパティを、要素のinnerText・innerXMLとして記述できるようになる。 -MSDN > .NET Frameworkクラス ライブラリ > System.Windows.Markup.ContentPropertyAttributeクラス~ http://msdn.microsoft.com/ja-jp/library/system.windows.markup.contentpropertyattribute.aspx --[ContentPropertyAttribute("Content")]→ Contentプロパティ --[ContentPropertyAttribute("Items")]→ Itemsコレクション プロパティ -コンテンツ構文 --プロパティ属性構文 <Button Content="Click Here" /> --プロパティ要素構文 <Button>Click Here</Button> なお、WindowsフォームやWebフォーム(HTML)などで、~ UIコントロールの表示のカスタマイズをするには、~ UIコントロールの「スタイル」属性の指定による方法のみサポートされていた。 これに対し、WPFのUIコントロールは「スタイル」属性の指定による方法だけでなく、~ Contentプロパティ(またはItemsコレクション プロパティ)に任意の型の子要素を設定することができるため、~ コントロールの「外観」を自由に変更でき、柔軟性が非常に高くなっている。 -補足:Windowsフォームの外観の変更 --Windowsフォームの「外観」を変更するには、コントロールを自前で描画する「オーナー描画」と呼ばれる方法が用意されていた。~ しかしながら、「オーナー描画」はグラフィックス メソッドなどを使用して、すべての描画を独自に行わなければならないため、コントロールに対する深い知識と多量のコードが必要であった。 --関連資料 ---[[.NETコントロールのカスタマイズ方法]] **Contentプロパティ [#gc84bde8] WPFのContentControlは、Contentプロパティに任意の型の子要素を設定することができるため、コントロールの「外観」を自由に変更できる。 ***文字列のコンテンツ要素を格納 [#m12672f2] #ref(ContentString.png,left,nowrap,レンダリング結果) ContentControlのButtonコントロールを例にしてContentプロパティへ要素を設定する例を示す。 -プロパティ属性構文: <Button Width="200" Height="200" Content="ボタン"/> -プロパティ要素構文: <Button Width="200" Height="200">ボタン</Button> ***イメージのコンテンツ要素を格納 [#faf81a9f] #ref(ContentImage.png,left,nowrap,レンダリング結果) Contentプロパティには、Imageオブジェクトなどの任意の型の要素も設定できる。 <Button Width="200" Height="200"> <Button.Content> <Image Source=".\Blue hills.jpg"/> </Button.Content> </Button> ***パネルに纏めた複数のコンテンツ要素を格納 [#a73fa28e] #ref(ContentStringAndImage.png,left,nowrap,レンダリング結果) -2つ以上の要素を設定したい場合は、パネル要素を使用する。 <Button Width="200" Height="200"> <Button.Content> <StackPanel Orientation="Vertical"> <Image Source=".\Blue hills.jpg" Margin="5" /> <TextBlock Text="ボタン" HorizontalAlignment="Center" Margin="5"/> </StackPanel> </Button.Content> </Button> -なお、<Object.Content>タグは省略することもできる。 <Button Width="200" Height="200"> <StackPanel Orientation="Vertical"> <Image Source=".\Blue hills.jpg" Margin="5" /> <TextBlock Text="ボタン" HorizontalAlignment="Center" Margin="5"/> </StackPanel> </Button> **Itemsプロパティ [#v7960713] WPFのItemsControlは、Itemsコレクション プロパティに任意の型の子要素を設定することができるため、コントロールの「外観」を自由に変更できる。 ***複数のパネルに纏めた複数のコンテンツ要素を格納 [#w0ea6ec9] ItemsControlのItemsコレクション プロパティへは、複数のコンテンツを追加できる。~ 以下、ListBoxコントロールを例にしてItemsコレクション プロパティへ子要素の設定する例を示す。 #ref(ItemsControl.png,left,nowrap,レンダリング結果) -複数のパネルに纏めた複数のコンテンツ要素を格納 <Grid> <ListBox> <Border BorderBrush ="Black" BorderThickness ="1" Margin="5"> <StackPanel Orientation="Horizontal" Height="120" Width="250" Margin="5"> <Image Source=".\Blue hills.jpg" Height="100"/> <TextBlock Text="Blue hills" VerticalAlignment="Center"/> </StackPanel> </Border> <Border BorderBrush ="Black" BorderThickness ="1" Margin="5"> <StackPanel Orientation="Horizontal" Height="120" Width="250" Margin="5"> <Image Source=".\Sunset.jpg" Height="100"/> <TextBlock Text="Sunset" VerticalAlignment="Center"/> </StackPanel> </Border> <Border BorderBrush ="Black" BorderThickness ="1" Margin="5"> <StackPanel Orientation="Horizontal" Height="120" Width="250" Margin="5"> <Image Source=".\Water lilies.jpg" Height="100"/> <TextBlock Text="Water lilies" VerticalAlignment="Center"/> </StackPanel> </Border> <Border BorderBrush ="Black" BorderThickness ="1" Margin="5"> <StackPanel Orientation="Horizontal" Height="120" Width="250" Margin="5"> <Image Source=".\Winter.jpg" Height="100"/> <TextBlock Text="Winter" VerticalAlignment="Center"/> </StackPanel> </Border> </ListBox> </Grid> -Itemsコレクション プロパティに子要素を設定する場合は、~ innerText・innerXMLを使用する「[[プロパティ要素構文>#fa957fd3]]」を使用する。 -また、この際に<Object.Items>タグは省略することもできる。 -ちなみに、上記を「データ バインディング」で実装することもできる。~ これについては、「[[データ バインディングの基礎>#bbd76ce0]]」を参照のこと。 *リソース [#p50dd8ac] ここでは、 -「リソース」の定義方法と、 -前述の各「マークアップ拡張」を使用し、~ プロパティ値に「リソース」への参照を指定する方法 について説明する。 ※「リソース」の「データ バインディング」については、~ 「[[リソースとのデータ バインディング>#ac5a7f33]]」を参照のこと。 -参考 --MSDN > WPFの基礎 > リソース~ http://msdn.microsoft.com/ja-jp/library/ms742538.aspx **リソースの定義 [#g7e2fd50] 「リソース」とは、ResourceDictionary 型のオブジェクトであり、 -ApplicationオブジェクトのResources プロパティ -各UI要素(FrameworkElement or FrameworkContentElement)のResources プロパティ に「プロパティ要素構文」を使用して定義できる。 -MSDN > .NET Frameworkクラス ライブラリ -- > System.Windows.ResourceDictionaryクラス~ http://msdn.microsoft.com/ja-jp/library/system.windows.resourcedictionary.aspx -- > System.Windows.Application.Resourcesプロパティ~ http://msdn.microsoft.com/ja-jp/library/system.windows.application.resources.aspx -- > System.Windows.FrameworkElement.Resourcesプロパティ~ http://msdn.microsoft.com/ja-jp/library/system.windows.frameworkelement.resources.aspx -- > System.Windows.FrameworkContentElement.Resourcesプロパティ~ http://msdn.microsoft.com/ja-jp/library/system.windows.frameworkcontentelement.resources.aspx このため、任意のUI要素に定義可能であるが、~ 通常はルート要素(Window or Page)上に定義する。~ また、「リソース」は、定義場所により以下のような呼称・特徴がある。 ***リソースの定義場所 [#qe6a5b64] -アプリケーション リソース~ ApplicationオブジェクトのResourcesプロパティに定義された「リソース」を~ 「アプリケーション リソース」と呼び、全体から(つまりどこからでも)参照できるという特徴を持っている。 -ウィンドウ ページ リソース~ Window・PageオブジェクトのResourcesプロパティに定義された「リソース」を~ 「アプリケーション リソース」と呼び、そのWindow・Pageと、その子要素から参照できるという特徴を持っている。 -イミディエイト リソース~ 各UI要素(FrameworkElement or FrameworkContentElement)の~ Resourcesプロパティに定義された「リソース」を「イミディエイト・リソース」と呼び、~ 「リソース」を定義した要素と、その子要素から参照できるという特徴を持っている。 ***リソースの定義例 [#sedc736a] -「リソース」には、前述のx:Key ディレクティブを使用して一意のキーを持たせて定義する必要がある。~ <Window.Resources> <x:Array x:Key="List" Type="{x:Type sys:String}"> <sys:String>A</sys:String> <sys:String>B</sys:String> <sys:String>C</sys:String> </x:Array> </Window.Resources> >※ 先頭で、String型のインポートが必要 xmlns:sys="clr-namespace:System;assembly=mscorlib" -補足:ジェネリック コレクションのリソース~ ジェネリック コレクションを「リソース」に定義するには、x:TypeArgumentsのディレクティブを使用して、~ ObservableCollection<T>コレクション クラスなどのジェネリック型のコンストラクタに渡す必要があるが、~ これは、XAML2009 からのサポートとなる。 ***リソースの使用方法 [#r6badd32] 「リソース」を定義したら、各種「マークアップ拡張」を使用して、~ プロパティ値に「データ バインディング」や、「リソース」への参照を指定できる。 この時、参照する側からx:Key ディレクティブを使用して割り当てたキーを「リソース」検索のキーとして指定できる。 なお、「スタイル」や「テンプレート」などは、キーを定義せず、TargetType 属性のみ使用して、~ 指定の型のオブジェクトに「スタイル」や「テンプレート」を適用することもできる。~ これについては、「[[スタイルとテンプレート>#q002601b]]」を参照のこと。 -MSDN > .NET Frameworkクラス ライブラリ -- > System.Windows.Style.TargetType プロパティ~ http://msdn.microsoft.com/ja-jp/library/system.windows.style.targettype.aspx -- > System.Windows.Controls.ControlTemplate.TargetTypeプロパティ~ http://msdn.microsoft.com/ja-jp/library/system.windows.controls.controltemplate.targettype.aspx **リソースの定義と参照 [#wd960230] 以下、「リソース」の定義と、プロパティ値に「リソース」への参照を指定する例を示す。 ***StaticResource参照の例 [#ybb9b94a] StaticResource参照では、 -コンパイル時に「リソース」検索が行われ、各「リソース」に指定されたキーが存在するかどうかが確認される。 -「リソース」検索により、「リソース」が発見できなかった場合は、コンパイル時にエラーとなる。 以下は、StaticResourceの定義と参照例。 -StaticResourceの定義と参照例(1) --以下は、「マークアップ拡張」を使用して、「プロパティ属性構文」でStaticResource参照した例である。 --また、属性名を省略すると自動的にコンストラクタに渡される動作を利用して、~ ResourceKey属性に指定の値を渡す旨を指示する「ResourceKey=」という記述を省略することができる。 > <Window.Resources> <SolidColorBrush x:Key="BlueBrush" Color="Blue"/> </Window.Resources> <Grid> <Ellipse Fill="{StaticResource ResourceKey=BlueBrush}" Height="150" Width="150"/> </Grid> >↓ 「ResourceKey =」という記述を省略 > <Window.Resources> <SolidColorBrush x:Key="BlueBrush" Color="Blue"/> </Window.Resources> <Grid> <Ellipse Fill="{StaticResource BlueBrush}" Height="150" Width="150"/> </Grid> #ref(StaticResource.png,left,nowrap,StaticResourceの定義と参照例(1)) -StaticResourceの定義と参照例(2)~ 以下は、一般的ではないが「プロパティ要素構文」を使用してStaticResource参照した例である。~ なお、WPFのみ、StaticResource参照を「プロパティ要素構文」で記述可能である。 > <Window.Resources> <SolidColorBrush x:Key="BlueBrush" Color="Blue"/> </Window.Resources> <Grid> <Ellipse Height="150" Width="150"> <Ellipse.Fill> <StaticResource ResourceKey="BlueBrush"/> </Ellipse.Fill> </Ellipse> </Grid> ***DynamicResource参照の例 [#h04a05da] -DynamicResource参照では、アプリケーションの起動時に、~ 後で「リソース」検索を行う際に使用する一時的な式が作成され、~ アプリケーションの実行後、「リソース」が必要になった際に都度、「リソース」検索が行われる。 -このためDynamicResource参照は、 --主に「リソース」の値が変更される場合、StaticResource参照に代替して使用する。 --「リソース」検索により、「リソース」が発見できなかった場合は、デフォルト値が設定される。 -なお、DynamicResource参照は、WPFでのみ利用可能で、「Silverlight」では利用不可である。 以下は、DynamicResourceの定義と参照例。 -以下は、リソースがアプリケーション外部から変更される場合の例~ 以下は、デスクトップ画面のテーマの変更(Windows XP → Windowsクラシック)を反映する例である。~ > <Grid> <Grid.RowDefinitions> <RowDefinition/> <RowDefinition/> </Grid.RowDefinitions> <Ellipse Grid.Row="0" Fill="{StaticResource ResourceKey={x:Static SystemColors.HighlightBrushKey}}"/> <Ellipse Grid.Row="1" Fill="{DynamicResource ResourceKey={x:Static SystemColors.HighlightBrushKey}}"/> </Grid> #ref(DynamicResource1.png,left,nowrap,DynamicResourceの定義と参照例(リソースがアプリケーション外部から変更される場合)) -以下は、リソースがアプリケーション内部から変更される場合の例~ 以下は、アプリケーションからの「リソース」の動的な変更を反映する例である。~ なお、「リソース」の動的な変更は、FrameworkElement.Resourcesプロパティで変更できる。 --XAML <Window.Resources> <SolidColorBrush x:Key="MyBrush" Color="Blue"/> </Window.Resources> <Grid> <Grid.RowDefinitions> <RowDefinition/> <RowDefinition/> <RowDefinition Height="23"/> </Grid.RowDefinitions> <Ellipse Grid.Row="0" Fill="{StaticResource MyBrush}"/> <Ellipse Grid.Row="1" Fill="{DynamicResource MyBrush}"/> <StackPanel Grid.Row="2" Orientation="Horizontal" HorizontalAlignment="Center"> <Button Content="青" Height="23" Name="button1" Width="75" Click="button1_Click" /> <Button Content="赤" Height="23" Name="button2" Width="75" Click="button2_Click" /> </StackPanel> </Grid> --コードビハインド private void button1_Click(object sender, RoutedEventArgs e) { this.Resources["MyBrush"] = Brushes.Blue; } private void button2_Click(object sender, RoutedEventArgs e) { this.Resources["MyBrush"] = Brushes.Red; } #ref(DynamicResource2.png,left,nowrap,DynamicResourceの定義と参照例(リソースがアプリケーション内部から変更される場合) ***StaticResource参照 + ディクショナリ ファイルの例 [#k8074527] ResourceDictionaryは、「ディクショナリ ファイル」に定義することもできる。 「ディクショナリ ファイル」を追加する際は、 +プロジェクト ファイルを右クリックし、 +[追加] → [リソース ディクショナリ]を選択するか、~ [追加] → [新しい項目]を選択し、表示されるテンプレートから[リソース ディクショナリ(WPF)]を選択する。 #ref(AddDictionary.png,left,nowrap,ディクショナリ ファイルの追加) -前述のStaticResource参照の例を、~ 「ディクショナリ ファイル」を使用するように書き直した例を以下に示す。 <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> <SolidColorBrush x:Key="BlueBrush" Color="Blue"/> </ResourceDictionary> ''ディクショナリ ファイルの定義例 (Dictionary1.xaml)'' -「ディクショナリ ファイル」を「イミディエイト・リソース」にロードする。 <Window.Resources> <ResourceDictionary Source="Dictionary1.xaml"/> </Window.Resources> <Grid> <Ellipse Fill="{StaticResource BlueBrush}" Height="150" Width="150"/> </Grid> > #ref(StaticResourceAndDictionary.png,left,nowrap,StaticResource参照 + ディクショナリ ファイルの使用例) ''StaticResource参照 + ディクショナリ ファイルの使用例'' ***DynamicResource参照 + ディクショナリ ファイルの例 [#z0de9556] -DynamicResource参照とResourceDictionaryを組み合わせ、 -ResourceDictionaryを、Application.LoadComponentで動的にロード、 -Application.Current.Resourcesに設定することにより、 -「スタイル」(スキン )などの設定をアプリケーションから動的に変更することが可能である。 以下の、その例を示す。 -Dictionary --Dictionary1.xaml <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> <SolidColorBrush x:Key="MyBrush" Color="Blue"/> </ResourceDictionary> --Dictionary2.xaml <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> <SolidColorBrush x:Key="MyBrush" Color="Red"/> </ResourceDictionary> -XAML <StackPanel> <Ellipse Fill="{DynamicResource MyBrush}" Height="150" Width="150"/> <Button Content="青" Height="23" Name="button1" Width="75" Click="button1_Click" /> <Button Content="赤" Height="23" Name="button2" Width="75" Click="button2_Click" /> </StackPanel> -コードビハインド public partial class Window1 : Window { public Window1() { InitializeComponent(); this.LoadResourceDictionary("Dictionary1.xaml"); } private void button1_Click(object sender, RoutedEventArgs e) { this.LoadResourceDictionary("Dictionary1.xaml"); } private void button2_Click(object sender, RoutedEventArgs e) { this.LoadResourceDictionary("Dictionary2.xaml"); } private void LoadResourceDictionary(string name) { ResourceDictionary dictionary = (ResourceDictionary)Application.LoadComponent(new Uri(name, UriKind.Relative)); if (dictionary != null) Application.Current.Resources = dictionary; } } > #ref(DynamicResourceAndDictionary.png,left,nowrap,DynamicResource参照 + ディクショナリ ファイルの使用例) ''DynamicResource参照 + ディクショナリ ファイルの使用例'' *データ バインディング [#w4afa32c] 様々なソースと「データ バインディング」するサンプルを示す。 なお、サンプルのXAMLソースを読むためには、以下の、~ Bindingプロパティの設定方法を理解しておく必要がある。 ''Bindingプロパティの設定方法'' |項番|プロパティ|説明|h |1|Mode|OneTime、OneWay、TwoWay のいずれかの「バインディング モード」を指定する。| |2|Source|「バインディング ソース」を指定する。「バインディング ソース」は、&br;「[[リソース>#ea30adb6]]」に定義し、[[StaticResourceの「マークアップ拡張」>#f8bba188]]を使用して「データ バインディング」するか、&br;FrameworkElement.DataContextから、「データ バインディング」する。| |3|ElementName|UI要素名を使用して「バインディング ソース」を指定する。| |4|RelativeSource|「バインディング ターゲット」からの相対位置で「バインディング ソース」を指定する。&br;※ Self、TemplatedParent、AncestorType、AncestorLevel属性などを使用して指定する。| |5|Path|「バインディング ソース」のプロパティ名を指定する(名前空間のフルパスで指定可)。&br;なお、インデクサなどの指定も可能である。詳細は、以下のURLを参照のこと。| |6|XPath|「バインディング ソース」として、XMLデータソースのXML DOMへのパスを表す文字列を指定する。| |7|TargetNullValue|ソース値が null のときに返される値を指定する。| |8|Converter|「[[値コンバータ>WPFのアーキテクチャ#nf7e2b6a]]」を指定する。&br;「[[値コンバータ>WPFのアーキテクチャ#nf7e2b6a]]」は、インスタンス化が可能であり、ResourceDictionaryに配置できる。&br;「[[値コンバータ>WPFのアーキテクチャ#nf7e2b6a]]」は「[[StaticResource>#ea30adb6]]」に定義し[[StaticResourceの「マークアップ拡張」>#f8bba188]]を使用して参照するようにする。| |9|ConverterCulture|「[[値コンバータ>WPFのアーキテクチャ#nf7e2b6a]]」で使用するカルチャを指定する。| |10|ConverterParameter|「[[値コンバータ>WPFのアーキテクチャ#nf7e2b6a]]」の変換ロジックで使用するパラメタを指定する。| -MSDN > ・・・ > バインディングのマークアップ拡張機能~ http://msdn.microsoft.com/ja-jp/library/ms750413.aspx --MSDN > ・・・ > PropertyPathのXAML構文~ http://msdn.microsoft.com/ja-jp/library/ms742451.aspx --MSDN > ・・・ > 方法:XMLDataProviderとXPathクエリを試用してXMLデータにバインドする~ http://msdn.microsoft.com/ja-jp/library/ms749287.aspx **データ バインディングの基礎 [#h0ae3316] 以下、「[[WPFのアーキテクチャ - データ バインディング>WPFのアーキテクチャ#dac6f2bf]]」に対応するサンプルを示す。 ***コードビハインドからのデータ バインディング(モード:OneWay) [#o2aaa11e] -モード:OneWayの「データ バインディング」を行う。 -「データ バインディング」の基本的な動作を理解するために、 --Bindingオブジェクトをコード ビハインドで自作し、 --以下の2つのオブジェクトを結びつける。 ---「バインディング ソース」 ---「バインディング ターゲット」 -XAML <StackPanel x:Name="MainPanel" Loaded="MainPanel_Loaded"> <TextBlock x:Name="TextBlock1"/> <TextBlock x:Name="TextBlock2"/> </StackPanel> -コードビハインド public partial class Window1 : Window { public Window1() { InitializeComponent(); } private void MainPanel_Loaded(object sender, RoutedEventArgs e) { // バインディング ソース(Person) Person BindingSource = new Person() { Height = 1.7, Weight = 60 }; // Bindingオブジェクトによりバインド // HeightプロパティをOneWayでバインド Binding BindingHeight = new Binding("Height"); BindingHeight.Mode = BindingMode.OneWay; // バインディング ソース(Person) BindingHeight.Source = BindingSource; // バインディング ターゲット(TextBlock) TextBlock1.SetBinding(TextBlock.TextProperty, BindingHeight); // WeightプロパティをOneWayでバインド Binding BindingWeight = new Binding("Weight"); BindingWeight.Mode = BindingMode.OneWay; // バインディング ソース(Person) BindingWeight.Source = BindingSource; // バインディング ターゲット(TextBlock) TextBlock2.SetBinding(TextBlock.TextProperty, BindingWeight); } } /// <summary>バインディング ソース(Person)</summary> public class Person { public double Height { get; set; } public double Weight { get; set; } } ***コードビハインドからのDataContextを使用したデータ バインディング(モード:OneWay) [#mb48f656] 上記のMainPanel_Loadedメソッドのコードを一部編集し、MainPanel(StackPanel)の~ FrameworkElement.DataContextプロパティに「バインディング ソース」を設定することで、~ Bindingオブジェクトへの「バインディング ソース」の指定が不要になる。 -コードビハインド private void MainPanel_Loaded(object sender, RoutedEventArgs e) { // バインディング ソース(Person) MainPanel.DataContext = new Person() { Height = 1.7, Weight = 60 }; // Bindingオブジェクトによりバインド // HeightプロパティをOneWayでバインド Binding BindingHeight = new Binding("Height"); BindingHeight.Mode = BindingMode.OneWay; // バインディング ターゲット(TextBlock) this.TextBlock1.SetBinding(TextBlock.TextProperty, BindingHeight); // WeightプロパティをOneWayでバインド Binding BindingWeight = new Binding("Weight"); BindingWeight.Mode = BindingMode.OneWay; // バインディング ターゲット(TextBlock) TextBlock2.SetBinding(TextBlock.TextProperty, BindingWeight); } ***BindingオブジェクトをXAMLで実装する(プロパティ要素構文) [#q82f9eb1] -BindingオブジェクトをXAMLのマークアップ機能で実装する。~ 更に、XAMLのマークアップ機能を使用して、Bindingオブジェクトの生成処理・設定処理をXAML側に移動することで、~ 上記のXAMLとMainPanel_Loadedメソッドのコードを一部編集し、コード ビハインドのコード量を削減できる。 --XAML <StackPanel x:Name="MainPanel" Loaded="MainPanel_Loaded"> <TextBlock> <TextBlock.Text> <Binding Path="Height" Mode="OneWay"/> </TextBlock.Text> </TextBlock> <TextBlock> <TextBlock.Text> <Binding Path="Weight" Mode="OneWay"/> </TextBlock.Text> </TextBlock> </StackPanel> --コードビハインド private void MainPanel_Loaded (object sender, RoutedEventArgs e) { // バインディング ソース(Person) MainPanel.DataContext = new Person() { Height = 1.7, Weight = 60 }; } -BindingオブジェクトをXAMLのバインディングのマークアップ拡張で実装する。~ 一般的には、「データ バインディング」を実装する場合、~ XAML側の記述は「バインディングのマークアップ拡張」により~ 「プロパティ属性構文」化して実装する方法を採る。 --更に、上記のXAMLを「バインディングのマークアップ拡張」を使用して、~ 「プロパティ属性構文」化して実装すると次のようになる。 <StackPanel x:Name="MainPanel" Loaded="MainPanel_Loaded"> <TextBlock Text="{Binding Path=Height, Mode=OneWay}" /> <TextBlock Text="{Binding Path=Weight, Mode=OneWay}" /> </StackPanel> --また、属性名を省略すると自動的にコンストラクタに渡される動作を利用して、~ (Path属性に指定の値を渡す旨を指示する)「Path=」という記述を省略することができる。 <StackPanel x:Name="MainPanel" Loaded="MainPanel_Loaded"> <TextBlock Text="{Binding Height, Mode=OneWay}" /> <TextBlock Text="{Binding Weight, Mode=OneWay}" /> </StackPanel> ***変更通知の追加(モード:OneWay or OneWayToSource) [#iffee571] 下記は、モード:OneWay or OneWayToSourceを併用した「データ バインディング」によるBMI(肥満度)の自動計算アプリケーションの例である。~ この例では、「バインディング ソース」のプロパティ値の変更を、自動的に「バインディング ターゲット」に反映できる。~ なお、この際、「バインディング ソース」は、INotifyPropertyChangedインターフェイスを実装して、BMI(肥満度)プロパティの変更通知処理を実装する必要がある。 -XAML <StackPanel x:Name="MainPanel" Loaded="MainPanel_Loaded"> <TextBox Margin="10" Text="{Binding Height, Mode=OneWayToSource}"/> <TextBox Margin="10" Text="{Binding Weight, Mode=OneWayToSource}"/> <Button Margin="10" Content="計算" Click="Button_Click" /> <TextBlock Margin="10" Text="{Binding Bmi, Mode=OneWay}"/> </StackPanel> -コードビハインド /// <summary>/// Window1.xaml の相互作用ロジック/// </summary> public partial class Window1 : Window { public Window1() { InitializeComponent(); } /// <summary>初期化イベント</summary> private void MainPanel_Loaded(object sender, RoutedEventArgs e) { // バインド ソース(Person) MainPanel.DataContext = new Person(); } /// <summary>計算イベント</summary> private void Button_Click(object sender, RoutedEventArgs e) { ((Person)MainPanel.DataContext).Calculate(); } } -バインディングソース /// <summary>バインド ソース(Person)</summary> public class Person : INotifyPropertyChanged { public double Height { get; set; } public double Weight { get; set; } double _bmi; public double Bmi { get { return this._bmi; } set { this._bmi = value; // 変更通知 this.OnPropertyChanged("Bmi"); } } /// <summary>計算処理</summary> public void Calculate() { this.Bmi = Weight / Math.Pow(Height, 2); } #region INotifyPropertyChanged メンバ /// <summary>値変更イベントの定義</summary> public event PropertyChangedEventHandler PropertyChanged; /// <summary>変更通知(値変更イベントを発生させる)</summary> protected virtual void OnPropertyChanged(string propertyName) { PropertyChangedEventHandler handler = this.PropertyChanged; if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName)); } #endregion } ***値コンバータの使用(モード:OneWay or OneWayToSource) [#jd1ebb3c] 続いて、上記処理に、BMI(肥満度)プロパティが -18.5未満の場合、出力先のTextBlockの背景色を青色に -25以上の場合、出力先のTextBlockの背景色を赤色に 変更する処理を追加する。 これには別途、背景色プロパティを定義することで実現することも可能であるが、~ ここでは、前述のIValueConverterインターフェイスを実装した「値コンバータ」を実装することでこれを実現する。~ 値の変換処理は、「値コンバータ」のConvertメソッドに実装する。 -XAML <Window.Resources> <my:BmiLevelConverter x:Key="bmiLevelConverter"/> </Window.Resources> <StackPanel x:Name="MainPanel" Loaded="MainPanel_Loaded"> <TextBox Margin="10" Text="{Binding Height, Mode=OneWayToSource}"/> <TextBox Margin="10" Text="{Binding Weight, Mode=OneWayToSource}"/> <Button Margin="10" Content="計算" Click="Button_Click" /> <TextBlock Margin="10" Text="{Binding Bmi, Mode=OneWay}" Background="{Binding Bmi, Mode=OneWay, Converter={StaticResource bmiLevelConverter}}"/> </StackPanel> -値コンバータ /// <summary>BMIレベルに合った背景色を返す</summary> public class BmiLevelConverter : IValueConverter { #region IValueConverter メンバ /// <summary>変換メソッド(ソースからターゲット)</summary> public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { // BMIレベルに合った背景色を返す double target = (double)value; SolidColorBrush level; if (target < 18.5) level = new SolidColorBrush(Colors.Blue); else if (target > 25) level = new SolidColorBrush(Colors.Red); else level = new SolidColorBrush(Colors.White); return level; } /// <summary>変換メソッド(ターゲットからソース)</summary> public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { throw new NotImplementedException(); } #endregion } ***INotifyPropertyChangedの変更通知を「依存関係プロパティ」で代替 [#xdb6404a] なお、変更通知は、INotifyPropertyChangedインターフェイスの実装ではなく、「依存関係プロパティ」でも代替できる。~ 上記の例のBMI(肥満度)プロパティを「依存関係プロパティ」として、以下のように書き直し、動作を確認する。~ -バインディングソース /// <summary>バインド ソース(Person)</summary> public class Person : DependencyObject { public double Height { get; set; } public double Weight { get; set; } /// <summary>Bmiプロパティを依存関係プロパティとして登録</summary> public static readonly DependencyProperty BmiProperty = DependencyProperty.Register("Bmi", typeof(double), typeof(Person), new UIPropertyMetadata(0.0)); /// <summary>BmiプロパティのCLRプロパティ</summary> public double Bmi { get { return (double)this.GetValue(Person.BmiProperty); } set { this.SetValue(Person.BmiProperty, value); } } /// <summary>計算処理</summary> public void Calculate(){ this.Bmi = Weight / Math.Pow(Height, 2); } } BMI(肥満度)プロパティが変更されると、UI要素(TextBlock)に変更が反映されることを確認できる。~ このように、「依存関係プロパティ」は既定で変更通知をサポートしている。 ***双方向のデータ バインディング(モード:TwoWay) [#q577d96c] 以下の例では、モード:TwoWayの「データ バインディング」を行うため、~ 2つのUI要素、TextBoxとSliderを双方向接続した例である。 なお前述のようにUI要素の表示に関するプロパティは、~ 基本的に「依存関係プロパティ」として定義されており、~ 既定で変更通知をサポートしている。このため、既定で双方向接続が可能である。 なお、「バインディング ソース」をUI要素に接続する場合は、ElementName属性を使用すると良い。 -TextBox(ソース)→Slider(ターゲット) --XAML <StackPanel Orientation="Vertical"> <Label>TextBox</Label> <TextBox x:Name="textBox1" Text="5"/> <Rectangle Height="20"></Rectangle> <Label>Slider</Label> <Slider x:Name="Slider1" Value="{Binding ElementName=textBox1, Path=Text, Mode=TwoWay}"/> </StackPanel> -Slider(ソース)→TextBox(ターゲット) --バインディング ソース、バインディング ターゲットを反転する。 --すると「バインディング ターゲット」(TextBox)の変更が直ちに通知されなくなる。~ (TextBoxから、フォーカスが外れないとSliderに変更値が反映されない)。 --これは、ほとんどの依存関係プロパティの既定値は PropertyChangedであるが、Textプロパティの既定値は LostFocusのため。 --この場合、「バインディングのマークアップ拡張」に、「UpdateSourceTrigger=PropertyChanged」 という属性の記述を追加することで、~ 「バインディング ターゲット」(TextBox)からの変更が直ちに「バインディング ソース」(Slider)に通知されるようになる。 --XAML <StackPanel Orientation="Vertical"> <Label>TextBox</Label> <TextBox x:Name="textBox1" Text="{Binding ElementName=Slider1, Path=Value, Mode=TwoWay}"/> <Rectangle Height="20"></Rectangle> <Label>Slider</Label> <Slider x:Name="Slider1" Value="5"/> </StackPanel> --MSDN > .NET Frameworkクラス ライブラリ > System.Windows.Data.Binding ---UpdateSourceTriggerプロパティ~ http://msdn.microsoft.com/ja-jp/library/system.windows.data.binding.updatesourcetrigger.aspx ---UpdateSourceTrigger列挙体~ http://msdn.microsoft.com/ja-jp/library/system.windows.data.updatesourcetrigger.aspx ***値コンバータの使用(モード:TwoWay) [#gdc1bedf] 双方向の値の変換に対応した「値コンバータ」は、~ Convert、ConvertBackメソッドの双方を実装する必要がある。 -XAML <Window.Resources> <my:ValConverter x:Key="valConverter" /> </Window.Resources> <StackPanel Orientation="Vertical"> <Label>TextBox</Label> <TextBox x:Name="textBox1" Text="500"/> <Rectangle Height="20"></Rectangle> <Label>Slider</Label> <Slider x:Name="Slider1" Value="{Binding ElementName=textBox1, Path=Text, Mode=TwoWay, Converter={StaticResource valConverter}}"/> </StackPanel> -コードビハインド public class ValConverter : IValueConverter { #region IValueConverter メンバ /// <summary>変換メソッド(ソースからターゲット)</summary> public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { return int.Parse(value.ToString()) / 100; } /// <summary>変換メソッド(ターゲットからソース)</summary> public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { return ((double)value) * 100; } #endregion } ***ItemsSourceへのデータ バインディング [#qe911f6c] ItemsControlから派生した要素のItemsSource属性にコレクションを「データ バインディング」する場合、対象オブジェクトは反復処理をサポートしている必要がある。 -ItemsSourceへのデータ バインディング(UI要素を含まない「データ バインディング」)~ 以下は、ObservableCollection<T> コレクション クラスを使用して「データ バインディング」する例である。~ なお、ObservableCollection<T>コレクション クラスは、INotifyPropertyChangedインターフェイスを継承しており、変更通知が可能となっている。 --XAML <StackPanel x:Name="stackPanel1"> <ListBox x:Name="listBox1" ItemsSource="{Binding}"/> <Button Height="23" Name="button1" Click="button1_Click">Button</Button> </StackPanel> --コードビハインド public partial class Window1 : Window { ObservableCollection<string> _cities = new ObservableCollection<string>(); public Window1() { InitializeComponent(); this._cities.Add("札幌市"); this._cities.Add("仙台市"); this._cities.Add("静岡市"); this.stackPanel1.DataContext = _cities; } private void button1_Click(object sender, RoutedEventArgs e) { this._cities.Add("神戸市" + this.listBox1.Items.Count.ToString()); } } --UI要素を含まない「データ バインディング」の実装例について、 ---上記例では、button1_ClickイベントでItemがObservableCollection<T>コレクションに追加さると直ちにListBoxの表示に反映されることが確認できる。~ また、この変更通知をサポートしているObservableCollection<T>コレクション クラスを、変更通知をサポートしないCollection<T> コレクション クラスに変更した場合、~ Collection<T>コレクションに追加されたItemがListBoxの表示に反映されないことも確認できる。 ---なお、変更通知に対応したカスタム コレクションを作成する場合は、~ ObservableCollection<T>や、Collection<T> & INotifyCollectionChangedを継承したカスタム コレクションを作成すると良い。 ---この際の注意点としては、後者のCollection<T> & INotifyCollectionChangedを継承したカスタム コレクションを作成する場合、~ Add、RemoveAtなどのメソッドに変更通知を実装し、「変更通知の基盤処理」の値変更イベントに、~ 前述のPropertyChangedEventHandlerではなく、NotifyCollectionChangedEventHandlerを使用する点である。 -ItemsSourceへのデータ バインディング(UI要素を含んだ「データ バインディング」)~ 以下は、[[「Itemsプロパティ」>#v7960713]]の例を「データ バインディング」で実装した例である。 --XAML <StackPanel x:Name="stackPanel1"> <ListBox ItemsSource="{Binding}"/> </StackPanel> --コードビハインド public Window1() { InitializeComponent(); // バンディング ソース(コレクション) ObservableCollection<Border> cities = new ObservableCollection<Border>(); // ワーク Border tmpBorder = null; StackPanel tmpStackPanel = null; Image tmpImage = null; TextBlock tmpTextBlock = null; // Borderの構築 tmpBorder = new Border(); tmpBorder.BorderBrush = Brushes.Black; tmpBorder.BorderThickness = new Thickness(1); tmpBorder.Margin = new Thickness(5); // StackPanelの構築 tmpStackPanel = new StackPanel(); tmpStackPanel.Orientation = Orientation.Horizontal; tmpStackPanel.Height = 120; tmpStackPanel.Width = 250; tmpStackPanel.Margin = new Thickness(5); // Imageの構築 tmpImage = new Image(); tmpImage.Source=new BitmapImage( new Uri(@".\Water lilies.jpg", UriKind.Relative)); tmpImage.Height=100; // TextBlockの構築 tmpTextBlock = new TextBlock(); tmpTextBlock.Text="Water lilies"; tmpTextBlock.VerticalAlignment = VerticalAlignment.Center; // 階層構造の組み立て tmpStackPanel.Children.Add(tmpImage); tmpStackPanel.Children.Add(tmpTextBlock); tmpBorder.Child = tmpStackPanel; // バンディング ソース(コレクション)に追加 cities.Add(tmpBorder); // ・・・(n項繰り返し)・・・ // データ バンディング stackPanel1.DataContext = cities; } --UI要素を含んだ「データ バインディング」の実装例について、 ---子要素を持つUI要素をコードビハインドで作成し、これを「データ バインディング」する実装例も、一般的ではない。 ---このような場合は、「テンプレート」を使用するのが一般的である。 ---「テンプレート」を使用した実装例は、「[[スタイルとテンプレート>#j0c577be]]」 - 「[[テンプレート>#o64ea160]]」を参照のこと。 ***インデクサによるデータ バインディング [#t27b49c9] インデクサについても、Path属性に角括弧を指定することで接続可能である。 -XAML <Grid> <Image x:Name="Image1" Height="200" Width="200" Source="{Binding Path=[Source]}" ToolTip="{Binding Path=[ToolTip]}"/> </Grid> -コードビハインド public Window1() { InitializeComponent(); Hashtable ht = new Hashtable(); ht["Source"] = @".\Winter.jpg"; ht["ToolTip"] = "Winter"; this.Image1.DataContext = ht; } これらを応用すると、~ インデクサを持つオブジェクトの配列(反復処理をサポート)~ をデータ バインディングすることも可能であることが分かる。 ビジネス・アプリケーションでは、DataGridへDataTableをデータ バインディングする際に、~ DataGridの列へDataTableの列をマッピングするようなケースでよく利用します。 **リソースとのデータ バインディング [#eb81566f] 「リソース」参照を「バインディングのマークアップ拡張」でも使用することができる。 ***StaticResourceを使用したデータ バインディング [#q416a676] -例えば、静的な「リソース」を使用し、以下のように「データ バインディング」できる。 --StaticResourceのデータ バインディング (1) <Window.Resources> <sys:String x:Key="val">Click Here</sys:String > </Window.Resources> <StackPanel> <Button Content="{Binding Source={StaticResource val}}"/> </StackPanel> ※ 先頭で、String型のインポートが必要 xmlns:sys="clr-namespace:System;assembly=mscorlib" -ItemsControlから派生したUIコントロールのItemsSource属性に「データ バインディング」する場合、~ 「リソース」の対象オブジェクトは反復処理をサポートしている必要がある。 --StaticResourceのデータ バインディング (2) <Window.Resources> <x:Array x:Key="list" Type="{x:Type sys:String}"> <sys:String>A</sys:String> <sys:String>B</sys:String> <sys:String>C</sys:String> </x:Array> </Window.Resources> <StackPanel> <ListBox ItemsSource="{Binding Source={StaticResource list}}"/> </StackPanel> ※ 先頭で、String型のインポートが必要 xmlns:sys="clr-namespace:System;assembly=mscorlib" ***DynamicResourceを使用したデータ バインディング [#e00226e0] 動的な「リソース」を使用した「データ バインディング」はサポートされない。~ 以下、「{Binding Source={DynamicResource」をテストした際のエラーメッセージである。 型 'Binding' の 'Source' プロパティで 'DynamicResourceExtension' を設定することはできません。'DynamicResourceExtension' は、DependencyObject の DependencyProperty でのみ設定できます。 -参考 --MSDN > .NET Frameworkクラス ライブラリ --- > System.Windows.Data.Binding.Sourceプロパティ~ http://msdn.microsoft.com/ja-jp/library/system.windows.data.binding.source.aspx --- > System.Windows.DynamicResourceExtensionクラス~ http://msdn.microsoft.com/ja-jp/library/system.windows.dynamicresourceextension.aspx *レイアウト [#lc8aa2dd] ココでは、レイアウト方法として、 -[[レイアウトのプロパティ>#ad27e006]] -[[パネルの種類と使い方>#t2926641]] の2つについて説明する。 -MSDN > WPFの基礎 > レイアウト システム~ http://msdn.microsoft.com/ja-jp/library/ms745058.aspx **レイアウトのプロパティ [#ad27e006] -ココでは、「レイアウト」関係のプロパティについて説明する。 -これらのプロパティは、「レイアウト」機能を追加するFrameworkElement基本クラスにより提供される。 --配置の際、各要素間に余白を指定したい場合は、Margin、Padding属性を使用する。 ---Margin :自要素と親要素の間 ---Padding:自要素と子要素の間~ ※ [left, top, right, bottom]と設定可能。省略時の動作は、リファレンスを参照のこと。 --配置の際、「揃え」を指定したい場合は、HorizontalAlignment、VerticalAlignment属性を使用する。 ---HorizontalAlignment :水平方法の揃え(Center、Left、Right、Stretchを指定可) ---VerticalAlignment :垂直方法の揃え(Center、Top、Bottom、Stretchを指定可)~ ※ Stretchは、引き伸ばして余白を埋めて配置の意味。 -以下、「レイアウト」関係のプロパティを使用したXAMLとレンダリングの例を示す。 --XAML <Border Background="LightBlue" BorderBrush="Black" BorderThickness="2" Padding="15"> <StackPanel Background="White" HorizontalAlignment="Center" VerticalAlignment="Top"> <TextBlock Margin="5,0,5,0" HorizontalAlignment="Center">Alignment, Margin and Padding Sample</TextBlock> <Button HorizontalAlignment="Left" Margin="20">Button 1</Button> <Button HorizontalAlignment="Right" Margin="10">Button 2</Button> <Button HorizontalAlignment="Stretch" Margin="0">Button 3</Button> </StackPanel> </Border> --[[レンダリング>https://i-msdn.sec.s-msft.com/dynimg/IC155786.jpeg]] -参考 --MSDN > WPFの基礎 > 基本要素 > 配置、余白、パディングの概要~ http://msdn.microsoft.com/ja-jp/library/ms751709.aspx **パネルの種類と使い方 [#t2926641] WPFでは、パネルを使用した「レイアウト」が可能である。 -パネルには、以下のような特徴がある。 --複数のUIElementを含めることができる(UIElementCollection のプロパティを持つ)。 ---MSDN > .NET Frameworkクラス ライブラリ > System.Windows.Controls.UIElementCollectionクラス~ http://msdn.microsoft.com/ja-jp/library/system.windows.controls.uielementcollection.aspx >UIElement子要素の順序付けられたコレクションを表す。~ XAMLから「[[プロパティ要素構文>#fa957fd3]]」の「[[コンテンツ構文>#m4c088a5]]」でパネル要素に子要素を追加する場合は、~ <Panel.Children>タグを使用する(ただし、このタグを明示しなくとも、暗黙的に使用される)。~ また、コード ビハインドから、パネル要素に子要素を追加する場合は、Children.Add メソッドを使用する。 --自分に含まれるUIElementを管理する。 --パネル自体もUIElementであるため、パネルへの組み込みが可能 -使用可能なパネル要素には次のものがある。 |#|パネル名|クラス名|説明|h |1|キャンバス パネル|Canvas|座標を使用して子要素を明示的に配置できる領域を定義する。| |2|ドック パネル|DockPanel|パネルの各「辺」に、子要素をドッキングする領域を定義する。| |3|スタック パネル|StackPanel|子要素を水平方向または垂直方向に整列する領域を定義する。| |4|折り返しパネル|WrapPanel|子要素を水平方向または垂直方向に整列し、端に達したら改行して整列する領域を定義する。| |5|(均一)グリッド パネル|UniformGrid|列と行で構成されているグリッド領域を定義する。| |6|グリッド パネル|Grid|列と行で構成されている柔軟なグリッド領域を定義する。| -また、親要素であるパネルへ配置する子要素の座標などの情報については、~ 子要素から「添付プロパティ」を使用して設定可能である。 ***キャンバス パネル [#p5a51a2b] -座標を使用して子要素を明示的に配置できる領域を定義する。 --XAML <Canvas Background="LightSteelBlue"> <TextBlock Canvas.Top="10" Canvas.Left="20"> Hello World! </TextBlock> <TextBlock Canvas.Top="40" Canvas.Left="50"> 絶対位置決め方式は便利ではありませんか? </TextBlock> </Canvas> --レンダリング結果 #ref(RenderingResultOfCanvas.png,left,nowrap,キャンバス パネルのレンダリング結果) -キャンバス パネルでは、「添付プロパティ」であるCanvas.Top・Canvas.Left属性を使用して、~ 子要素から座標位置を明示的に指定・配置できるため、Windowsフォームに近い開発が可能である。 -参考 --MSDN > .NET Frameworkクラス ライブラリ > System.Windows.Controls.Canvasクラス~ http://msdn.microsoft.com/ja-jp/library/system.windows.controls.canvas.aspx ***ドック パネル [#pe1b48eb] -パネルの各「辺」に、子要素をドッキングする領域を定義する。 --XAML <DockPanel LastChildFill="True"> <Border Height="25" Background="SkyBlue" DockPanel.Dock="Top"> <TextBlock Foreground="Black">Dock = "Top(1)"</TextBlock> </Border> <Border Height="25" Background="SkyBlue" DockPanel.Dock="Top"> <TextBlock Foreground="Black">Dock = "Top(2)"</TextBlock> </Border> <Border Height="25" Background="LemonChiffon" DockPanel.Dock="Bottom"> <TextBlock Foreground="Black">Dock = "Bottom"</TextBlock> </Border> <Border Width="100" Background="PaleGreen" DockPanel.Dock="Left"> <TextBlock Foreground="Black">Dock = "Left"</TextBlock> </Border> <Border Background="White"> <TextBlock Foreground="Black"> This content will "Fill" the remaining space </TextBlock> </Border> </DockPanel> --レンダリング結果 #ref(RenderingResultOfDockPanel.png,left,nowrap,ドック パネルのレンダリング結果) -DockPanel.LastChildFillプロパティ(LastChildFill属性)をtrue (既定値)に設定すると、~ DockPanelの最終の子要素は常に残りの領域を埋めるようになる。 -参考 --MSDN > .NET Frameworkクラス ライブラリ > System.Windows.Controls.DockPanelクラス~ http://msdn.microsoft.com/ja-jp/library/system.windows.controls.dockpanel.aspx ***スタック パネル [#i49c2e00] -子要素を水平方向または垂直方向に整列する領域を定義する。 --XAML ---水平方向 <StackPanel Orientation="Horizontal"> <RadioButton Margin="4">test1</RadioButton> <RadioButton Margin="4">test2</RadioButton> <RadioButton Margin="4">test3</RadioButton> </StackPanel> ---垂直方向 <StackPanel Orientation="Vertical"> <RadioButton Margin="4">test1</RadioButton> <RadioButton Margin="4">test2</RadioButton> <RadioButton Margin="4">test3</RadioButton> </StackPanel> --レンダリング結果 ---水平方向 #ref(HorizontalRenderingResultOfStackPanel.png,left,nowrap,スタック パネルの水平レンダリング結果) ---垂直方向 #ref(VerticalRenderingResultOfStackPanel.png,left,nowrap,スタック パネルの垂直レンダリング結果) -整列方向は、StackPanel.Orientationプロパティ(Orientation属性)で指定する。 -参考 --MSDN > .NET Frameworkクラス ライブラリ > System.Windows.Controls.StackPanelクラス~ http://msdn.microsoft.com/ja-jp/library/system.windows.controls.stackpanel.aspx ***折り返しパネル [#c1367ccd] -子要素を水平方向または垂直方向に整列し、端に達したら改行して整列する領域を定義する。~ ※ パネルのサイズが変更されると、改行位置も変更される。 --XAML ---水平方向 <WrapPanel Orientation="Horizontal"> <Button Width="26" Height="26" Margin="4" Content="0"></Button> <Button Width="26" Height="26" Margin="4" Content="1"></Button> <Button Width="26" Height="26" Margin="4" Content="2"></Button> ・・・ <Button Width="26" Height="26" Margin="4" Content="7"></Button> <Button Width="26" Height="26" Margin="4" Content="8"></Button> <Button Width="26" Height="26" Margin="4" Content="9"></Button> </WrapPanel> ---垂直方向 <WrapPanel Orientation="Vertical"> <Button Width="26" Height="26" Margin="4" Content="0"></Button> <Button Width="26" Height="26" Margin="4" Content="1"></Button> <Button Width="26" Height="26" Margin="4" Content="2"></Button> ・・・ <Button Width="26" Height="26" Margin="4" Content="7"></Button> <Button Width="26" Height="26" Margin="4" Content="8"></Button> <Button Width="26" Height="26" Margin="4" Content="9"></Button> </WrapPanel> --レンダリング結果 ---水平方向 #ref(HorizontalRenderingResultOfWrapPanel.png,left,nowrap,折り返しパネルの水平レンダリング結果) ---垂直方向 #ref(VerticalRenderingResultOfWrapPanel.png,left,nowrap,折り返しパネルの垂直レンダリング結果) -整列方向は、WrapPanel.Orientationプロパティ(Orientation属性)で指定する。 -参考 --MSDN > .NET Frameworkクラス ライブラリ > System.Windows.Controls.WrapPanelクラス~ http://msdn.microsoft.com/ja-jp/library/system.windows.controls.wrappanel.aspx ***(均一)グリッド パネル [#h66a8f8e] -列と行で構成されているグリッド領域を定義する。~ ※ グリッド内のすべてのセルが同じサイズである必要がある。 --XAML ---3行 * 4列 <UniformGrid Rows="3" Columns="4"> <Button Width="26" Height="26" Margin="4" Content="0"></Button> <Button Width="26" Height="26" Margin="4" Content="1"></Button> <Button Width="26" Height="26" Margin="4" Content="2"></Button> ・・・ <Button Width="26" Height="26" Margin="4" Content="7"></Button> <Button Width="26" Height="26" Margin="4" Content="8"></Button> <Button Width="26" Height="26" Margin="4" Content="9"></Button> </UniformGrid> ---4行 * 3列 <UniformGrid Rows="4" Columns="3"> <Button Width="26" Height="26" Margin="4" Content="0"></Button> <Button Width="26" Height="26" Margin="4" Content="1"></Button> <Button Width="26" Height="26" Margin="4" Content="2"></Button> ・・・ <Button Width="26" Height="26" Margin="4" Content="7"></Button> <Button Width="26" Height="26" Margin="4" Content="8"></Button> <Button Width="26" Height="26" Margin="4" Content="9"></Button> </UniformGrid> --レンダリング結果 ---3行 * 4列 #ref(RenderingResultOfUniformGrid34.png,left,nowrap,(均一)グリッド パネルの3行 * 4列レンダリング結果) ---4行 * 3列 #ref(RenderingResultOfUniformGrid43.png,left,nowrap,(均一)グリッド パネルの4行 * 3列レンダリング結果) -行・列数は、UniformGrid.Rows、UniformGrid.Columns属性(UniformGrid. Rows・Columnsプロパティ)で指定する。 -参考 --MSDN > .NET Frameworkクラス ライブラリ > System.Windows.Controls.UniformGridクラス~ http://msdn.microsoft.com/ja-jp/library/system.windows.controls.primitives.uniformgrid.aspx ***グリッド パネル [#p94f8aa7] -列と行で構成されている柔軟なグリッド領域を定義する。 --行・列の定義にGrid.RowDefinitions、Grid.ColumnDefinitionsタグを使用する。 ---「添付プロパティ」であるGrid.Row・Grid.Column属性を使用して子要素をセルへ配置する。 ---列長・行長の設定も、この属性で指定する。 ---このためHTMLのテーブルと使い方は異なる。 --XAML ( 4行 * 3列 <Grid Width="250" Height="100"> <Grid.ColumnDefinitions> <ColumnDefinition /> <ColumnDefinition /> <ColumnDefinition /> </Grid.ColumnDefinitions> <Grid.RowDefinitions> <RowDefinition /> <RowDefinition /> <RowDefinition /> <RowDefinition /> </Grid.RowDefinitions> <TextBlock Grid.ColumnSpan="3" Grid.Row="0">2005 Products Shipped</TextBlock> <TextBlock Grid.Row="1" Grid.Column="0">Quarter 1</TextBlock> <TextBlock Grid.Row="1" Grid.Column="1">Quarter 2</TextBlock> <TextBlock Grid.Row="1" Grid.Column="2">Quarter 3</TextBlock> <TextBlock Grid.Row="2" Grid.Column="0">50000</TextBlock> <TextBlock Grid.Row="2" Grid.Column="1">100000</TextBlock> <TextBlock Grid.Row="2" Grid.Column="2">150000</TextBlock> <TextBlock Grid.ColumnSpan="3" Grid.Row="3">Total Units: 300000</TextBlock> </Grid> --レンダリング結果 #ref(RenderingResultOfGrid43.png,left,nowrap,グリッド パネルの4行 * 3列レンダリング結果) -なお、ColumnDefinitionタグのWidth属性に" n*"と指定することで、比率を指定できる。 --XAML ( 比率を指定 <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="1*"></ColumnDefinition> <ColumnDefinition Width="2*"></ColumnDefinition> <ColumnDefinition Width="3*"></ColumnDefinition> </Grid.ColumnDefinitions> <Grid.RowDefinitions> <RowDefinition Height="1*"></RowDefinition> <RowDefinition Height="2*"></RowDefinition> <RowDefinition Height="3*"></RowDefinition> </Grid.RowDefinitions> </Grid> --レンダリング結果 #ref(RenderingResultOfGridRatio.png,left,nowrap,グリッド パネル比率のレンダリング結果) -参考 --MSDN > .NET Frameworkクラス ライブラリ > System.Windows.Controls.Gridクラス~ http://msdn.microsoft.com/ja-jp/library/system.windows.controls.grid.aspx *スタイルとテンプレート [#j0c577be] ココでは、「外観」に関する設定を行う「[[スタイル>#v30d5ab6]]」と「[[テンプレート>#o64ea160]]」について説明する。 -参考 --MSDN > WPFの基礎 > スタイルとテンプレート : 概念~ http://msdn.microsoft.com/ja-jp/library/bb613570.aspx ---> スタイルとテンプレート~ http://msdn.microsoft.com/ja-jp/library/ms745683.aspx ---> ControlTemplateの作成による既存のコントロールの外観のカスタマイズ~ http://msdn.microsoft.com/ja-jp/library/ee230084.aspx --MSDN > Windows Presentation Foundation > コントロール ---> コントロールのカスタマイズ > ControlTemplateの例~ http://msdn.microsoft.com/ja-jp/library/aa970773.aspx **スタイル [#v30d5ab6] ***スタイルの基本 [#x9dade50] 「スタイル」は、UI要素の「依存関係プロパティ」の一括管理機能を持ち、これを使用して「外観」に統一性を持たせるための機能である。~ 「スタイル」は、Style型のオブジェクトであり、各UI要素(FrameworkElement or FrameworkContentElement)のStyleプロパティに指定可能である。 -外観に関する値を設定する「プロパティ属性構文」~ 以下は、UI要素の「依存関係プロパティ」に、「外観」に関するFill、Height、Width属性の属性値を設定する「プロパティ属性構文」である。 --XAML <Grid> <Ellipse Fill="Blue" Height="80" Width="160"/> </Grid> --レンダリング結果 #ref(RenderingResultOfStyle1.png,left,nowrap,外観に関する値を設定する「プロパティ属性構文」) -プロパティ属性構文のスタイル化 --上記を、「プロパティ要素構文」を使用してStyle型のオブジェクトを生成し、Styleプロパティにこれを指定する例を以下に示す。 ---TargetType属性により、「スタイル」は指定の型(ここではEllipse要素)に適用される。 ---このTargetType属性による型指定が無いと、対象のプロパティの有・無などが判別できないため、型指定は必須となっている。 --XAML <Grid> <Ellipse> <Ellipse.Style> <Style TargetType="Ellipse"> <Setter Property="Fill" Value="Blue"/> <Setter Property="Height" Value="80"/> <Setter Property="Width" Value="160"/> </Style> </Ellipse.Style> </Ellipse> </Grid> --レンダリング結果 #ref(RenderingResultOfStyle2.png,left,nowrap,プロパティ属性構文のスタイル化) -スタイルをリソースとして定義 --なお、上記の「スタイル」化は、通常のプロパティ設定を冗長に記述しているに過ぎず、何の意味もなさない。 --このため、通常、「スタイル」を「リソース」として定義し、各UI要素のStyleプロパティにはStaticResource参照を使用して設定する。 --以下は、x:Keyを明示した例である。 ---XAML <StackPanel.Resources> <Style x:Key="EllipseStyle" TargetType="Ellipse"> <Setter Property="Fill" Value="Blue"/> <Setter Property="Height" Value="80"/> <Setter Property="Width" Value="160"/> </Style> </StackPanel.Resources> <Ellipse Style="{StaticResource EllipseStyle}"/> <Ellipse Style="{StaticResource EllipseStyle}"/> </StackPanel> ---レンダリング結果 #ref(RenderingResultOfStyle3.png,left,nowrap,スタイルをリソースとして定義) -ベースクラスの型にスタイルを適用~ また、派生元(ここではShape型)が同じであれば、異なる要素でも同じ「スタイル」を適用できる。 --XAML <StackPanel> <StackPanel.Resources> <Style x:Key="ShapeStyle" TargetType="Shape"> <Setter Property="Fill" Value="Blue"/> <Setter Property="Height" Value="80"/> <Setter Property="Width" Value="160"/> </Style> </StackPanel.Resources> <Ellipse Style="{StaticResource ShapeStyle}"/> <Rectangle Style="{StaticResource ShapeStyle}"/> </StackPanel> --レンダリング結果 #ref(RenderingResultOfStyle4.png,left,nowrap,ベースクラスの型にスタイルを適用) -スタイルを全体に適用する例~ x:Keyを設定しなければ、TargetType属性により、「スタイル」は指定の型(ここではEllipse型)、全体に適用される~ (ただし、派生元が同じだが、型の異なる全ての要素に「スタイル」を適用することはできない)。~ --XAML <StackPanel> <StackPanel.Resources> <Style TargetType="Ellipse"> <Setter Property="Fill" Value="Blue"/> <Setter Property="Height" Value="80"/> <Setter Property="Width" Value="160"/> </Style> </StackPanel.Resources> <Ellipse/> <Ellipse/> </StackPanel> --レンダリング結果 #ref(RenderingResultOfStyle5.png,left,nowrap,スタイルを全体に適用する例) ***スタイルの継承 [#g2818cb4] -TargetType プロパティが同じ2つのStyleクラスを定義し、~ BasedOnプロパティに継承元となるStyleクラスを設定することで、 >「スタイル」の継承が可能である。 >(Silverlight 2のStyleクラスにはBasedOnプロパティが存在しなかったが、Silverlight 3で追加されている) -スタイルの継承例 --XAML <StackPanel> <StackPanel.Resources> <Style x:Key="EllipseBaseStyle" TargetType="Ellipse"> <Setter Property="Fill" Value="Blue"/> <Setter Property="Height" Value="80"/> <Setter Property="Width" Value="160"/> </Style> <Style x:Key="EllipseInheritedStyle" TargetType="Ellipse" BasedOn="{StaticResource EllipseBaseStyle}"> <Setter Property="Stroke" Value="Yellow"/> <Setter Property="StrokeThickness" Value="10"/> </Style> </StackPanel.Resources> <Ellipse Style="{StaticResource EllipseBaseStyle}"/> <Ellipse Style="{StaticResource EllipseInheritedStyle}"/> </StackPanel> --レンダリング結果 #ref(RenderingResultOfInheritedStyle.png,left,nowrap,スタイルの継承例) ***外部ファイル化 [#je240854] -「ディクショナリ ファイル」を使用して、CSSファイルのように、~ 「スタイル」を外部ファイルに定義することも可能である。 -以下は、「ディクショナリ ファイル」を使用する例である。 --XAML <Window.Resources> <ResourceDictionary Source="Dictionary1.xaml"/> </Window.Resources> <StackPanel> <StackPanel.Resources> <Style x:Key="EllipseInheritedStyle" TargetType="Ellipse" BasedOn="{StaticResource EllipseBaseStyle}"> <Setter Property="Stroke" Value="Yellow"/> <Setter Property="StrokeThickness" Value="10"/> </Style> </StackPanel.Resources> <Ellipse Style="{StaticResource EllipseBaseStyle}"/> <Ellipse Style="{StaticResource EllipseInheritedStyle}"/> </StackPanel> --XAML ( 外部ファイル : Dictionary1.xaml <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> <Style x:Key="EllipseBaseStyle" TargetType="Ellipse"> <Setter Property="Fill" Value="Blue"/> <Setter Property="Height" Value="80"/> <Setter Property="Width" Value="160"/> </Style> </ResourceDictionary> ***実行時スタイル [#aef5f69e] -「[[リソースの定義と参照>#wd960230]]」の --DynamicResource参照 --ディクショナリ ファイル >の方法を、「スタイル」でも応用可能である。 -上記の例のXAMLを以下のように書き換え、~ コードビハインドからResourceDictionaryを切り換え~ 「スタイル」(スキン)を実行時に、動的に切り換えることができる。 --XAML <StackPanel> <Ellipse Style="{DynamicResource MyEllipseStyle}"/> <Button Content="青" Height="23" Name="button1" Width="75" Click="button1_Click" /> <Button Content="赤" Height="23" Name="button2" Width="75" Click="button2_Click" /> </StackPanel> --XAML ( 外部ファイル : ---Dictionary1.xaml <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> <Style x:Key="MyEllipseStyle" TargetType="Ellipse"> <Setter Property="Fill" Value="Blue"/> <Setter Property="Height" Value="80"/> <Setter Property="Width" Value="160"/> </Style> </ResourceDictionary> ---Dictionary2.xaml <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> <Style x:Key="MyEllipseStyle" TargetType="Ellipse"> <Setter Property="Fill" Value="Red"/> <Setter Property="Height" Value="160"/> <Setter Property="Width" Value="80"/> </Style> </ResourceDictionary> --コード・ビハインド public partial class Window1 : Window { public Window1() { InitializeComponent(); this.LoadResourceDictionary("Dictionary1.xaml"); } private void button1_Click(object sender, RoutedEventArgs e) { this.LoadResourceDictionary("Dictionary1.xaml"); } private void button2_Click(object sender, RoutedEventArgs e) { this.LoadResourceDictionary("Dictionary2.xaml"); } private void LoadResourceDictionary(string name) { ResourceDictionary dictionary = (ResourceDictionary)Application.LoadComponent(new Uri(name, UriKind.Relative)); if (dictionary != null) Application.Current.Resources = dictionary; } } --レンダリング結果 #ref(RenderingResultOfStyleAtRuntime.png,left,nowrap,実行時スタイル) **テンプレート [#o64ea160] ***テンプレートの基本 [#l20b9ab9] -「[[コンテンツ構文>#m4c088a5]]」でも述べたように、WPFのUIコントロールは --「スタイル」属性の指定だけでなく、 --Contentプロパティ(またはItemsコレクション プロパティ)に >任意の型の子要素を設定することができる。 -このため、WPFのUIコントロールはコントロールの「外観」を自由に変更でき、柔軟性が非常に高くなっている。 -また、「テンプレート」により、 --コントロールの「外観」を宣言型マークアップでカスタマイズ可能になる(「テンプレート」を複数の子要素から構成する)。 --また、「イベント ハンドラ」や「イベント トリガ」なども~ この「テンプレート」により定義可能で、「テンプレート」を「スタイル」化することで、~ 任意の型のコントロールに、これらの「テンプレート」の定義の適用を強制できる。 --ただし、「テンプレート」で作成できる「外観」は、静的なものに限られる。 -「テンプレート」は、コントロールの用途毎に、複数のものが用意されている。 --テンプレートを設定するのプロパティと、テンプレートの型 |#|テンプレートを設定するプロパティ|テンプレートのクラス型|説明|h |1|Control.Template|ControlTemplate|Control.Templateプロパティに設定するControlTemplateクラスは、Controlコントロールを表示する「テンプレート」を定義する際に使用する。| |2|ContentControl.ContentTemplate|DataTemplate|ContentControl.ContentTemplateプロパティに設定するDataTemplateクラスは、ContentControlコントロールのContentプロパティのデータを表示する「テンプレート」を定義する際に使用する。| |3|ItemsControl.ItemTemplate|DataTemplate|ItemsControl.ItemTemplateプロパティに設定するDataTemplateクラスは、ItemsControlコントロールのItemsコレクション プロパティのデータを使用する「テンプレート」を定義する際に使用する。| |4|HeaderTemplate、CellTemplateなど|DataTemplate|種々のコントロールに独自のテンプレートが存在する。| -参考 --MSDN > Windows Presentation Foundation ---> データ > データ バインディング > データ テンプレートの概要~ http://msdn.microsoft.com/ja-jp/library/ms742521.aspx --MSDN > .NET Frameworkクラス ライブラリ ---> System.Windows.Controls.Control.Templateプロパティ~ http://msdn.microsoft.com/ja-jp/library/system.windows.controls.control.template.aspx ---> System.Windows.Controls.ContentControl.ContentTemplateプロパティ~ http://msdn.microsoft.com/ja-jp/library/system.windows.controls.contentcontrol.contenttemplate.aspx ---> System.Windows.Controls.ItemsControl.ItemTemplateプロパティ~ http://msdn.microsoft.com/ja-jp/library/system.windows.controls.itemscontrol.itemtemplate.aspx ---> System.Windows.Controls.ControlTemplateクラス~ http://msdn.microsoft.com/ja-jp/library/system.windows.controls.controltemplate.aspx ---> System.Windows.DataTemplateクラス~ http://msdn.microsoft.com/ja-jp/library/system.windows.datatemplate.aspx -また、親コントロールに適用した、Contentプロパティ~ (またはItemsコレクション プロパティ)を含むプロパティ値を~ 「テンプレート」に反映させるにめには、下記の3通りの方法を使用できる。 --「プレゼンター」を利用する方法 ---親コントロールのContentプロパティの場合は、ContentPresenter を用いる。~ Contentプロパティは、任意の型の子要素を取得し、「テンプレート」に反映できる。 ---また、ItemsControlのItemsプロパティに対応するものにItemsPresenter があり、~ Itemsプロパティの並びを、ItemsControlのItemsPanel プロパティのItemsPanelTemplate で変更できる。 ---その他、コントロールによって、ScrollContentPresenter 、CellValuePresenterなどの「プレゼンター」が用意されている。 ---なお、DataTemplateは、~ ● ContentPresenter(Contentプロパティ)~ ● ItemsPresenter(Itemsプロパティ)~ の表示をカスタマイズするための「テンプレート」である。~ ~ このため、ControlTemplateとDataTemplateの両方のカスタマイズを行う場合は、~ ControlTemplate側に必ず、ContentPresenter・ItemsPresenterを含める必要がある点に注意が必要である。 --「マークアップ拡張」を使用する場合~ 親コントロールの任意のプロパティの場合、「マークアップ拡張」を使用する。 Property={TemplateBinding TargetProperty} --「マークアップ拡張」を使用する場合 親コントロールの任意のプロパティの場合、「マークアップ拡張」を使用する。 RelativeSource={RelativeSource TemplatedParent} *トリガ [#x73e9a3a] **プロパティ トリガ [#z60358ba] **データ トリガ [#af3def31] **イベント トリガ [#p908262c] ---- Tags: [[:.NET開発]], [[:UIサブシステム]], [[:WPF/Silverlight, XAML]]