過去記事
- WPF4.5入門 その1 「はじめに」
- WPF4.5入門 その2 「WPFとは」
- WPF4.5入門 その3 「Hello world」
- WPF4.5入門 その4 「Mainメソッドはどこにいった?」
- WPF4.5入門 その5 「全てC#でHello world」
- WPF4.5入門 その6 「WPFを構成するものを考えてみる」
- WPF4.5入門 その7 「XAMLのオブジェクト要素と名前空間」
- WPF4.5入門 その8 「オブジェクト要素のプロパティ」
- WPF4.5入門 その9 「コレクション構文」
- WPF4.5入門 その10 「コンテンツ構文」
- WPF4.5入門 その11 「マークアップ拡張」
- WPF4.5入門 その12 「その他のXAMLの機能」
- WPF4.5入門 その13 「簡単なレイアウトを行うコントロール」
- WPF4.5入門 その14 「レイアウトコントロールのCanvasとStackPanel」
- WPF4.5入門 その15 「レイアウトコントロールのDockPanelとWrapPanel」
- WPF4.5入門 その16 「ViewBoxコントロール」
- WPF4.5入門 その17 「ScrollViewerコントロール」
- WPF4.5入門 その18 「Gridコントロール part 1」
- WPF4.5入門 その19 「Gridコントロール part 2」
- WPF4.5入門 その20 「レイアウトに影響を与えるプロパティ」
少し間が空いてしまいました。ちょっとJavaに浮気してましたがWPFは、まだまだ続きます!ここまでレイアウトコントロールについて詳しく見てきましたが少し飽きてきたので、ちょっと横道にそれてWPFのコンセプトと、個人的に重要だと思ってる機能について、少し紹介したいと思います。
WPFのコンセプト
WPFのコンセプトはMSDNによると「UI、メディア、およびドキュメントを組み込んだ Windows スマート クライアントの豊富なユーザー エクスペリエンスを構築するための、統一されたプログラミング モデルを開発者に提供すること」です。また、ASP.NETなどで取り入れられたテンプレートを使った柔軟なレイアウトの構築や、CSSのように見た目の定義を共通化する方法などのWebアプリケーションを開発する上での優れた仕組みなども取り込まれています。
私の感想として、WPFは当時のGUIを開発するためのプラットフォームのいい点や反省点をマイクロソフトが本気で検討して実装しなおしたテクノロジだと思います。その結果、その後のUIを開発するためのプラットフォームはSilverlightやWindows PhoneやWindows ストア アプリでもWPFと同じXAMLとC#による開発が主になっています。WPFを学習するということは、マイクロソフトの提供するプラットフォーム上でのUIの開発をするうえでWPFのノウハウを活用できるという点でもおすすめです。(細かい差異はたくさんありますが…)
このようなコンセプトを実現するためのキーとなる部分として、以下の3つをここで簡単に紹介します。
- コンテンツモデルとデータテンプレート
- スタイル
- データバインディング
ここでは、こんなことが出来るんだという雰囲気をつかんでもらうことを目的としています。詳細な説明は、後半で行うのでそちらを参照してください。
コンテンツモデル
WPFでは、単一の要素を表示するコントロールとしてContentControlというものが定義されています。このコントロールは、ButtonやLabelなどの多くのコントロールの親クラスです。ContentControlにはContentという名前のobject型のプロパティが定義されていて、そこに設定されたクラスの型に応じて表示方法が切り替わります。表示ロジックは以下のようになっています。
- UIElement型(ButtonやRectangleなどのコントロール)の場合はそのまま表示する。
- ContentTemplateにデータテンプレートが設定されている場合は、それを使って表示する。
- Contentプロパティに設定された型に対してデータテンプレートが定義されている場合は、それを使って表示する。
- UIElement型へ変換するTypeConverterがある場合は、それを使ってUIElement型に変換して表示する。
- string型へ変換するTypeConverterがある場合は、それを使って文字列に変換してTextBlockのTextプロパティに設定して表示する。
- ToStringメソッドの呼び出し結果をTextBlockのTextプロパティに設定して表示する。
ここで特に重要なのは、Contentプロパティにコントロールが設定された場合は、そのまま表示できることと、その他のオブジェクトが設定された場合はデータテンプレートという仕組みを使って表示されることです。このシンプルな仕組みを理解することがWPFでデータを画面に表示する際にとても重要になります。
UIElementを表示する例
Buttonコントロールを使ってContentプロパティの表示を確認してみます。まずは、コントロールを設定した場合です。XAMLを以下に示します。
<Button HorizontalAlignment="Left" VerticalAlignment="Top"> <StackPanel Orientation="Horizontal" Margin="5"> <TextBlock Text="button" /> <Image Source="btn.png" Stretch="None" /> <TextBlock Text="button" /> </StackPanel> </Button>
これは、コードでも同じように記述できます。
var panel = new StackPanel { Orientation = Orientation.Horizontal, Margin = new Thickness(5) }; panel.Children.Add(new TextBlock { Text = "button" }); panel.Children.Add(new Image { Source = new BitmapImage(new Uri("btn.png", UriKind.Relative)), Stretch = Stretch.None }); panel.Children.Add(new TextBlock { Text = "button" }); var b = new Button { HorizontalAlignment = HorizontalAlignment.Left, VerticalAlignment = VerticalAlignment.Top, Content = panel };
文字列の表示
ToStringメソッドの呼び出し結果を表示できるので、当然文字列はそのまま表示できます。
<Button Content="文字列を設定" />
オブジェクトの表示
任意のクラスを設定した場合の例を示します。例えば以下のようなAnimalクラスがあるとします。
using System.Windows.Media.Imaging; public class Animal { public string Name { get; set; } public int Age { get; set; } public BitmapImage Picture { get; set; } }
このクラスをButtonのContentに設定して表示してみます。コードは以下のようになります(buttonObjectという名前のButtonクラスの変数があると仮定)。
// オブジェクトを作成 var anthem = new Animal { Name = "アンセム", Age = 9, Picture = new BitmapImage(new Uri("/anthem.png", UriKind.Relative)) }; // ボタンに設定 this.buttonObject.Content = anthem;
このボタンの表示は以下のようになります。
ToStringメソッドの結果が表示されていることが確認できます。これに、ButtonコントロールのContentTemplateプロパティにデータテンプレートを設定してみます。XAMLを以下に示します。
<Button Name="buttonObject" HorizontalAlignment="Left" VerticalAlignment="Top"> <Button.ContentTemplate> <DataTemplate> <StackPanel> <TextBlock Text="{Binding Name}" /> <TextBlock Text="{Binding Age, StringFormat={}{0}歳}" /> <Image Source="{Binding Picture}" Stretch="None" /> </StackPanel> </DataTemplate> </Button.ContentTemplate> </Button>
テンプレートを設定すると、ToStringメソッドの結果だったものが以下のような表示になります。
データテンプレートを使うと、データの表示をとても柔軟に制御できることが感じていただけると思います。
スタイル
WPFでは、スタイルという仕組みを使うことでコントロールのプロパティの設定を複数のコントロールで共通化することが出来ます。こうすることで、アプリケーション全体で統一した見た目を定義することが簡単に出来るようになります。スタイルを設定するには、コントロールのStyleプロパティにStyleを設定します。Styleは、Setterというオブジェクトを使って、どのプロパティにどんな値を設定するか指定できます。
スタイルを使って、背景色を黒、前景色を白に設定したXAMLを以下に示します。
<Button Content="スタイルの例"> <Button.Style> <Style TargetType="{x:Type Button}"> <Setter Property="Background" Value="Black" /> <Setter Property="Foreground" Value="White" /> </Style> </Button.Style> </Button>
このボタンを表示すると以下のようになります。
この方法だと、1つのボタンに直接スタイルを設定しているのであまり意味はありませんが、以下のようにリソースとしてスタイルの定義を外だしにすることで複数ボタンに共通のスタイルを設定することが出来ます。XAMLを以下に示します。
<Window x:Class="WpfApplication4.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" Height="350" Width="525"> <Window.Resources> <!-- スタイルをリソースに定義する --> <Style TargetType="{x:Type Button}"> <Setter Property="Background" Value="Black" /> <Setter Property="Foreground" Value="White" /> </Style> </Window.Resources> <StackPanel> <!-- 画面にボタンを複数置く --> <Button Content="スタイルの例1" /> <Button Content="スタイルの例2" /> <Button Content="スタイルの例3" /> <Button Content="スタイルの例4" /> <Button Content="スタイルの例5" /> </StackPanel> </Window>
先ほどButtonのStyleプロパティに直接設定されていたStyleの定義を外に移動させています。このWindowを表示すると以下のようになります。
複数のコントロールにスタイルが適用されていることが確認できます。
データバインディング
最後に、データバインディングの紹介をします。データバインディングは、コントロールのプロパティと任意のオブジェクトのプロパティを同期するための仕組みです。値の同期には、双方向と一方向が指定できます。
ソースの指定方法は、いろいろな方法がありますが一番よく使うのがコントロールのDataContextプロパティにソースとなるオブジェクトを設定する方法です。DataContextプロパティは、デフォルトで親の値を継承するためWindowのDataContextにソースとなるオブジェクトを設定するだけでWindow内のコントロールすべてのバインディングのソースとして設定できます。
バインディングの記述方法
バインディングは、XAMLで“{”と“}”で括った記法で書くのが一般的です。この記法はマークアップ拡張といわれるXAMLの記法です。ButtonコントロールのContentプロパティにDataContextに設定されているオブジェクトのFullNameプロパティの値をバインドするXAMLの例を以下に示します。
<Button Content="{Binding FullName}" />
Buttonを置いているWindowのDataContextに以下のようにオブジェクトを設定するとButtonのContentとバインドされます。
// DataContextにFullNameプロパティを持ったオブジェクトを設定 this.DataContext = new { FullName = "大田 一希" };
Windowを表示させると、以下のようにバインドできていることが確認できます。
今回は、ButtonコントロールのContentプロパティとバインドしましたがTextBoxコントロールのような、ユーザーの入力を受け取るコントロールとバインドすると、入力値をオブジェクトに反映することが出来ます。このように、宣言的に見た目と裏のデータを対応付け出来るため綺麗にデータと表示を分離することができます。コンテンツモデルとデータテンプレートの箇所のコード例でもバインディングを利用していましたが、データテンプレートと組み合わせることで自由自在にデータを画面に表示させることが出来るようになります。
まとめ
ここではWPFのコンセプトと、そのコンセプトを実現するために重要だと思うコンテンツモデル・データテンプレート・スタイル・データバインディングについて簡単に紹介しました。コンテンツモデルでは、単純なデータの表示から複雑なものの表示までが、とてもシンプルに実現できることを示しました。データテンプレートでは、オブジェクトを表示するための柔軟な仕組みがあることを示しました。スタイルでは、コントロールのプロパティを共通に定義することで、一貫した見た目のアプリケーションを簡単に作れることを示しました。データバインディングでは、コントロールのプロパティと、オブジェクトのプロパティを強力に結びつけることを示しました。
これらの機能は、WPFの膨大な機能のほんの一握りにすぎませんが、これだけで従来のデスクトップアプリケーションの開発では困難だった表現や、データと見た目を綺麗に分離したアプリケーションの開発が簡単に実現できることを感じ取って頂けたと思います。ここから先は、引き続きWPFの各機能の詳細について説明していきます。