次の方法で共有


Visual Studio 2010 自習書 ~ Do-It-Yourself シリーズ ~
XAML による Windows アプリケーション開発の基礎

第 4 回 データ バインディング

更新日: 2011 年 1 月 13 日

ダウンロード (XPS、970 KB | PDF、902 KB)


目次

  1. 今回作成するプログラム
  2. データ バインディングとは
  3. コントロール間のバインディング
  4. XML データをバインディング
    • バインディングのデータ源となる XML データを定義
    • コントロールに表示するデータの指定 (ItemsSource)
    • 表示方法の設定
  1. ADO.NET を用いたデータ バインディング
    • データベースの準備
    • バインド先の ListView の準備
    • DataSet の取得
  2. まとめ

XML Do-It-Yourself 第 4 回では、コントロール間のバインディングやデータ バインディングについて学びます。

ここでは次のことを学習します。

  • コントロール間のバインディング
  • XML データをバインディング
  • ADO.NET を用いたデータ バインディング

1. 今回作成するプログラム

今回は、ADO.NET を用いて データベースの内容をリスト ビューにバインドします。「レイアウト」の回で紹介したエクスプローラー風のアプリケーションに ListView を組み込んでいます。

ページのトップへ


2. データ バインディングとは

ADO.NET を用いて Windows フォーム アプリケーションを作成した経験のあるプログラマなら「バインディング」という言葉を何度も耳にしていることでしょう。ADO.NET を用いて取得したデータベースの内容を Windows フォーム上のコントロールに「バインド」することで、データベースの内容をコントロールに反映することが簡単に行えます。

同様にして、XAML (WPF) でもバインディング機能を利用することで、データとコントロールを同期させたり、コントロール間の同期を行ったりすることが可能になります。

ページのトップへ


3. コントロール間のバインディング

まず XAML に記述したコントロール間でのバインディングを行ってみましょう。

パネルに、楕円を描画する <Ellipse> 要素と <Slider>要素 (スライダー) を配置します。そして、Slider で設定する値が楕円の高さに反映されるようにバインディングを行います。

<Window x:Class="WpfApplication4.MainWindow"
                    xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
      Title="MainWindow" Height="300" Width="300">
      <DockPanel>
             <Slider DockPanel.Dock="Bottom" Height="22" Name="slider1" VerticalAlignment="Top" Maximum="300" Minimum="1" />
             <Ellipse Name="ellipse1" Stroke="Black" Fill="Red" Height="{Binding ElementName=slider1, Path=Value}" />
      </DockPanel>
</Window>

リスト 4-1 コントロール間のバインディング

<DocPanel> 要素には、<Ellipse> 要素と <Slider> 要素 を配置しています。<Slider> 要素には "slider1" という名前 (Name 属性) を付けています。<Slider> 要素は DockPanel パネルの下側に配置するように設定しています (DockPanel.Dock="Bottom")。

ウィンドウの残り部分には、内部が赤く塗りつぶされた楕円が描画されます。ここで次のようにして Ellipse の高さを指定する Height 属性でバインディングを指定しています。

Height="{Binding ElementName=slider1, Path=Value}"

これは、slider1 という名前の要素の "Value プロパティ" が示す内容を、Height プロパティにバインドする、という指定です。

<Slider> 要素では最小値を 1 に、最大値を 300 に設定しているため、スライダーのつまみをマウスで移動させると、1 から 300 までの間で、Slider の値である Value プロパティが変化します。その結果、スライダーの動きと同期して、楕円の高さ (Height) が 1 から 300 まで変化するというわけです。

このようにコントロール間でバインディングを利用することで、プログラム・コードを記述することなく、コントロール間の同期が簡単に行えます。

ページのトップへ


4. XML データをバインディング

コントロールにバインドできるのは、コントロールだけではありません。続いて、外部データをコントロールにバインドします。ここでは外部データとして XML ファイルを用意し、XML データに含まれる特定の要素を リスト ボックス に表示します。

XML データをコントロールにバインドして表示するには、大きく分けて次の 3 つの作業が必要です。

  • バインディングのデータ源となる XML データを定義
  • コントロールに表示するデータの指定 (ItemsSource)
  • 表示方法の設定

バインディングのデータ源となる XML データを定義

まず、リソースとして XML ファイルを定義します。リソースについては「第 5 回 リソース」で詳述しますので、ここではこういった記述を行うものとして考えてください。

<Window.Resources>
      <XmlDataProvider x:Key="BookData" Source="bookdata.xml" XPath="Inventory/Books"/>
</Window.Resources>

ここで、x:key 属性は、XAML ファイルの中で参照する際のリソースの名前を決めています。これにより、XML ファイルを "BookData" という名前で参照できます。次の Source 属性は、読み込む XML ファイル名を指定しています。bookdata.xml はXAML ファイルと同じフォルダーにあると仮定しています。ソリューション エクスプローラーでプロジェクト名を右クリックし、[追加] - [新しい項目] で表示されるダイアログ ボックスで、XML ファイルを追加すると、空の XML ファイルが作成されます。最後の XPath 属性は、参照する XML ファイルのどの部分を読み込むかを指定するものです。これは XML (XSLT) で使用する XPath の構文と同じルールです。この例では、<Inventory> 要素に含まれる <Books> 要素の内容を、"BookData" として扱うことを示しています。

読み込む XML ファイル (bookdata.xml) は、次に示すような内容になっているものとします。ルート タグが <Inventory> で、その中に <Books> タグが記述され、ここに複数の <Book> 要素が含まれています。<Book> 要素には、<Title>、<Summary> といった要素が含まれています。

<?xml version="1.0" encoding="UTF-8" ?>
<Inventory >
  <Books>
    <Book ISBN="0-7356-0562-9" Stock="in" Number="9">
      <Title>XML in Action</Title>
      <Summary>XML Web Technology</Summary>
    </Book>
    <Book ISBN="0-7356-1370-2" Stock="in" Number="8">
      <Title>Programming Microsoft Windows With C#</Title>
      <Summary>C# Programming using the .NET Framework</Summary>
    </Book>
    <Book ISBN="0-7356-1288-9" Stock="out" Number="7">
      <Title>Inside C#</Title>
      <Summary>C# Language Programming</Summary>
    </Book>
    <Book ISBN="0-7356-1377-X" Stock="in" Number="5">
      <Title>Introducing Microsoft .NET</Title>
      <Summary>Overview of .NET Technology</Summary>
    </Book>
    <Book ISBN="0-7356-1448-2" Stock="out" Number="4">
      <Title>Microsoft C# Language Specifications</Title>
      <Summary>The C# language definition</Summary>
    </Book>
  </Books>
</Inventory>

コントロールに表示するデータの指定 (ItemsSource)

ここでは XML ファイルの内容を ListBox に表示しますので、次に <ListBox> 要素の準備をします。

ListBox で項目を直接 XAML ファイル内に記述する場合は、次のように <ListItem> 要素を使って記述できます。

<ListBox>
      <ListBoxItem IsSelected="True">項目#1</ListBoxItem>
      <ListBoxItem >項目#2</ListBoxItem>
</ListBox>

しかし、表示する内容をコントロールの要素内で直接記述するのではなく、外部で用意する場合は、どこからそのデータを調達してくるかを指定する必要があります。これには ItemsSource プロパティを使用して次のように記述します。

<ListBox.ItemsSource>
      <Binding Source="{StaticResource BookData}" XPath="*" />
</ListBox.ItemsSource>

<ListBox.ItemSource> 要素の中では、さらに <Binding> 要素を用いて ListBox にバインドするデータを指定します。Source 属性では、先ほどリソースとして定義した BookData を指定します。さらに XPath 属性で ListBox に表示する内容を選択します。XPath についてはここでは触れませんが、指定している "*" は、任意のタグにマッチすることを示します。つまりすべての XML 要素にマッチします。

ここまでの記述で、リソースとして定義した BookData のデータを ListBox にバインドできました。

表示方法の設定

最後に ListBox の表示項目に対応する XML ファイルの要素を指定します。これには ItemTemplate プロパティを使用します。テンプレート (Template) については以降の回で詳述しますので、ここでは記述例を示すだけにとどめます。

<ListBox.ItemTemplate>
      <DataTemplate>
            <TextBlock FontSize="14" Text="{Binding XPath=Title}"/>
      </DataTemplate>
</ListBox.ItemTemplate>

<ListBox.ItemTemplate> 要素内で、<TextBlock> 要素を記述している部分が、ListBox の行の表示を定義している部分です。ここでは 14 ピクセルのフォント サイズで、<TextBlock> 要素の Text 属性にバインディングを指定しています。バインドするのは、XPath を使って指示している XML データ内の <Title> 要素です。

ListBox では、項目に何も指定しない場合は、文字列 (テキスト) により表示されます。しかし第 2 回で紹介したように、XAML では ListBox に項目として画像を表示するなどの、項目のカスタマイズが非常に簡単に行えます。

せっかく XML ファイルに <Title> 以外の要素も用意されているので、ここでは <Summary> タグの内容も一緒に表示するようにテンプレートを変更します。<Summary> 要素に対応する部分は、文字の色を赤 (Red) にし、バインディングに Summary を指定します。そして、2 つの TextBlock を 1 つの項目としてまとめるために、 StackPanel を使います。

<ListBox.ItemTemplate>
      <DataTemplate>
            <StackPanel>
                  <TextBlock FontSize="14" Text="{Binding XPath=Title}"/>
                  <TextBlock Foreground="Red" Text="{Binding XPath=Summary}"/>
            </StackPanel>
      </DataTemplate>
</ListBox.ItemTemplate>

以上をまとめると、最終的な XAML ファイルは次のようになります。

<Window x:Class="WpfApplication.MainWindow"
            xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
            Title="XML データのバインディング" Height="300" Width="400">
      <Window.Resources>
            <XmlDataProvider x:Key="BookData" Source="bookdata.xml" XPath="Inventory/Books"/>
      </Window.Resources>
      <Grid>
            <ListBox>
                  <ListBox.ItemsSource>
                        <Binding Source="{StaticResource BookData}" XPath="*" />
                  </ListBox.ItemsSource>
                  <ListBox.ItemTemplate>
                        <DataTemplate>
                              <StackPanel>
                                    <TextBlock FontSize="14" Text="{Binding XPath=Title}"/>
                                    <TextBlock Foreground="Red" Text="{Binding XPath=Summary}"/>
                              </StackPanel>
                        </DataTemplate>
                  </ListBox.ItemTemplate>
            </ListBox>
      </Grid>
</Window>

リスト 4-2 XML ファイルをバインドする

実行すると、次のように表示されます。

このようにして XML ファイルからデータを読み込んでコントロールにバインドできますが、ここで説明した XML ファイルの利用方法では、コンパイル時に XML ファイルがリソースとして読み込まれる点に注意してください。アプリケーションが起動する際に XML ファイルが読み込まれるのではありません (アプリケーションの実行時には XML ファイルは不要です)。

ページのトップへ


5. ADO.NET を用いたデータ バインディング

最後に、ADO.NET を用いてデータベース内のデータとのバインディング (データ バインディング) を行います。この場合には、ロジック (コード ビハインド) の記述が必要となります。もちろん、ADO.NET を使ってアクセスするデータベースも必要になります。

データベースの内容表示は表形式で行うと都合がよいので、ここでは ListView の詳細表示を使ってクエリの結果を表示します。

データベースの準備

今回の例では、マイクロソフトが配信する「MSDN Online 更新情報」の RSS フィードをベースに SQL Server 2008 上に作成したテーブルを使用します。データベース名は Syndication で、RSS フィードの内容が格納されたテーブルの名前は Items とします。

SQL Server 2008 に作成したテーブル

バインド先の ListView の準備

バインド先となる <ListView> 要素では、表示形式として表形式の GridView を使います。

まず、<ListView> 要素に Name 属性を使って "myListview" という名前を設定します。さらにこの ListView で表示するデータを ItemsSource 属性で指定します。ここには "{Binding Path=Items}" をセットします。これは "Items" という名前のテーブルをバインドすることを示しています。後述するように、ADO.NET によるクエリの実行結果を、今回は DataSet に格納しています。DataSet には複数のテーブルが格納できるため、Path を使ってテーブル名を指定する必要があります。DataTable や DataView といった単一のテーブルのデータしか返さないオブジェクトをバインドする場合は、Path の指定は不要になります。

次に <ListView> 要素の列情報を定義します。これには <GridViewColumn> 要素を使います。次のリストに示すように、列ごとに、幅 (Width)、見出し行の表示内容 (Header)、バインディングの指定を行います。

バインディングは DisplayMemberBinding 属性を使って、クエリ結果のどの列をバインドするかを指定します。その書式は ItemsSource 属性と同様で、この場合には、表示列に対応するテーブルのカラム名を指定します (Path=itemID など)。ここでは 4 つの列を定義することにより、クエリ結果から 4 つのカラムの値を表示します。

<Window x:Class="WpfApplication.Window1"
        xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
        Title="ADO.NET によるデータ バインディング" Height="300" Width="600">
  <Grid>
    <ListView Name="myListview" ItemsSource="{Binding Path=Items}" >
      <ListView.View>
        <GridView>
          <GridView.Columns>
            <GridViewColumn Width="50" Header="ID" DisplayMemberBinding="{Binding Path=itemID}" />
            <GridViewColumn Width="70" Header="公開日" DisplayMemberBinding="{Binding Path=pubDate}" />
            <GridViewColumn Width="300" Header="タイトル" DisplayMemberBinding="{Binding Path=title}" />
            <GridViewColumn Width="100" Header="カテゴリー" DisplayMemberBinding="{Binding Path=category}" />
          </GridView.Columns>
        </GridView>
      </ListView.View>
    </ListView>
  </Grid>
</Window>

DataSet の取得

ADO.NET を用いたデータ バインディングでは、データベースから取得した DataSet、DataTable、DataView などのオブジェクトを、XAML で記述したコントロールにバインドすることになります。

今回は <Window> 要素に対応するコード ビハインド ファイルのクラスのコンストラクター内でデータベースに接続し、DataSet を取得します。まず XAML ファイルで、<Window> 要素に対応するコード ビハインドのクラスを指定します。

<Window x:Class="WpfApplication.Window1"
      xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
      Title="ADO.NET によるデータ バインディング" Height="300" Width="600">

Visual Studio 2010 を利用してWPF アプリケーション プロジェクトを作成する場合は、コード ビハインド ファイルにはコンストラクターがあらかじめ定義済みです。

namespace WpfApplication
{
      /// <summary>
      /// Window1.xaml の相互作用ロジック
      /// </summary>
      public partial class Window1 : Window
      {
            public Window1()
            {
                  InitializeComponent();
                  getDataSet(); // DataSetを取得する
            }
      }
}

次に、クエリを実行して DataSet を作成する getDataSet メソッドをこのクラスに追加します。このメソッドでは Items テーブルの全レコードを取得します。DataSet を取得する際に、結果が格納される DataTable には "Items" という名前を付けています。

using System.Data.SqlClient;
using System.Data;

    ……

// SQL Server にアクセスして結果を得る
private void getDataSet()
{
  string connStr = @"Data Source=.\SQLEXPRESS;Initial Catalog=Syndication;Integrated Security=True";

  SqlConnection conn = new SqlConnection(connStr);
  try {
    conn.Open();
    SqlCommand cmd = new SqlCommand("", conn);
    string sSQL = String.Format("SELECT * FROM Items");

    SqlDataAdapter da = new SqlDataAdapter(sSQL,conn);
    DataSet ds = new DataSet();
    da.Fill(ds, "Items");

    myListview.DataContext = ds;
  } catch {
  } finally {
    conn.Close();
  }
}

ADO.NET のコードの記述についてはここで詳細は触れませんが、得られた DataSet オブジェクトを myListview.DataContext にセットしている点に注意してください。myListview は、XAML で定義した ListView の名前です。これにより myListview のバインド先が DataSet オブジェクトに設定されます。

実行すると、次のような表形式によりデータベースの内容が得られます。

「第 2 回 レイアウト」で最後に紹介したエクスプローラー風のウィンドウ レイアウトに、この ListView を組み込むことができます。

ページのトップへ


6. まとめ

今回は、コントロール間、XML データ、そして ADO.NET によるデータベースとのバインディングについて学習しました。ここでは触れていませんが、XML ファイルを動的に読み込みたい場合は、ADO.NET の場合と同様に、コード ビハインド クラスで XML ファイルを読み込み、XmlDocument や XmlDataProvider などのオブジェクトをコントロールにバインドすることで、データ バインディングが可能になります。

次回は XAML の記述を効率的に行う上で欠かせない、「リソース」について学習します。

ページのトップへ