Share via


Windows Presentation Foundation データ バインディング: パート 1

 

Shawn Wildermuth

2006 年 5 月

適用対象:
   Microsoft Windows Presentation Foundation

概要:XAML ベースのデータ バインディングを使用して、Microsoft Windows Presentation Foundation プロジェクトでデータ操作を実行する方法を示します。 (16ページ印刷)

内容

はじめに
XAML バインド、簡略化
ここはどこですか。
リファレンス

はじめに

Microsoft Windows Presentation Foundation (WPF、旧 Avalon) では、リッチ クライアント用のユーザー インターフェイスを開発するための新しい方法が導入されています。 WPF は初めて、ユーザー インターフェイスのデザインをコードから分離します。 この分離は、ASP.NET と同様に、マークアップは通常 1 つのファイルにあり、コードは別のファイルに存在することを意味します。 ただし、この分離はコンパイル時にのみ存在します。 マークアップ ファイルは、アプリケーションを生成するためにコード ファイルと結婚するコードを生成するために使用されます。

設計を容易にするために、Microsoft は XAML と呼ばれる豊富なマークアップ言語を開発しました。 XAML は XML ベースのマークアップ言語であり、2-D と 3-D の描画、アニメーション、コントロールの封じ込め、コントロール、ドキュメント フロー、豊富なデータ バインディング モデルなど、さまざまなユーザー インターフェイスの概念をネイティブにサポートするアプリケーションを開発するための新しいモデルをサポートします。 この記事では、WPF データ バインディングの概要について説明します。 この記事では、WPF に関する知識があることを前提としています。 そうでない場合は、概要については、Time Sneath の Hitchhiker の WPF ベータ 1 に関するガイド に関する記事を参照してください。

データ バインディングを使用する理由

WPF の使用を開始する場合は、データ バインディングの学習を避ける方が簡単かどうか疑問に思うかもしれません。代わりに、プロジェクトでほとんどのデータ操作を行うためのコードを記述するだけです。 これは有効な方法かもしれませんが、XAMLベースのデータバインディングを使用し、おそらく愛することさえあると思います。 小さな例を見てみましょう。

図 1 は、単純な WPF プロジェクトのユーザー インターフェイスを示しています。 RSS フィードのエディターであり、ユーザーがフィードを表示および編集できるようにします。

画像を大きくするにはここをクリック

図 1. RSS エディター (画像をクリックすると大きな画像が表示されます)

エディターのレイアウトは、次の XAML コードで次に示すように、非常に簡単です。

<Window x:Class="ExampleCS.Window1"
    xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
    Title="ExampleCS"
    Loaded="Window1_Loaded"
    >
  <StackPanel>
    <TextBlock HorizontalAlignment="Center" 
          FontWeight="Bold">
      BlogEditor
    </TextBlock>
    <StackPanel Orientation="Horizontal" 
           HorizontalAlignment="Center">
      <ListBox Name="entryListBox" 
          Height="300" 
          SelectionChanged="entryListBox_Changed"/>
      <Grid Width="500" Margin="5">
        <Grid.ColumnDefinitions>
          <ColumnDefinition Width="50" />
          <ColumnDefinition Width="*" />
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
          <RowDefinition Height="25" />
          <RowDefinition Height="25" />
          <RowDefinition Height="25" />
          <RowDefinition Height="*" />
          <RowDefinition Height="25" />
        </Grid.RowDefinitions>
        <TextBlock Grid.Row="0" Grid.Column="0">Title:</TextBlock>
        <TextBox Grid.Row="0" Grid.Column="1" Name="titleText" />
        <TextBlock Grid.Row="1" Grid.Column="0">Url:</TextBlock>
        <TextBox Grid.Row="1" Grid.Column="1" Name="urlText" />
        <TextBlock Grid.Row="2" Grid.Column="0">Date:</TextBlock>
        <TextBox Grid.Row="2" Grid.Column="1" Name="dateText" />
        <TextBlock Grid.Row="3" Grid.Column="0">Body:</TextBlock>
        <TextBox Grid.Row="3" Grid.Column="1" 
            Name="bodyText" 
            TextWrapping="Wrap" />
        <Button Grid.Row="4" 
                  Grid.ColumnSpan="2" 
                  Grid.Column="1"
            Click="updateButton_Click">
          Update
        </Button>
      </Grid>
    </StackPanel>
  </StackPanel>
</Window>

太字のイベント ハンドラーを書き留めます。 これは、RSS フィードを読み込んで WPF コントロールに入力するために、ほとんどのコードが発生する場所です。

C#

XmlDocument blog = new XmlDocument();
const string BLOGURL = @"z:\adoguy.RSS";

public Window1()
{
  InitializeComponent();
  blog.Load(BLOGURL);
}

void Window1_Loaded(object sender, RoutedEventArgs e) 
{
  FillListBox();
}

void FillListBox()
{
  entryListBox.Items.Clear();

  XmlNodeList nodes = blog.SelectNodes("//item");
  foreach (XmlNode node in nodes)
  {
    ListBoxItem item = new ListBoxItem();
    item.Tag = node;
    item.Content = node["title"].InnerText;
    entryListBox.Items.Add(item);
  }
}

Visual Basic .NET

  Dim blog As New XmlDocument
  Const BLOGURL As String = "z:\adoguy.RSS"

  Public Sub New()
    InitializeComponent()
    blog.Load(BLOGURL)
  End Sub

  Sub Window1_Loaded(ByVal sender As Object, _
                     ByVal e As RoutedEventArgs) 
    FillListBox()

  End Sub

  Sub FillListBox()

    entryListBox.Items.Clear()

    Dim nodes As XmlNodeList = blog.SelectNodes("//item")

    For Each node As XmlNode In nodes

      Dim item As New ListBoxItem
      item.Tag = node
      item.Content = node("title").InnerText
      entryListBox.Items.Add(item)

    Next

  End Sub

このコードでは、RSS フィードを使用して XML ドキュメントを読み込み、 ListBox にすべてのエントリのタイトルを入力していることがわかります。

次に、 ListBox で選択が行われた場合の処理を行う必要があります。

C#

void entryListBox_Changed(object sender, RoutedEventArgs e)
{
  if (entryListBox.SelectedIndex != -1)
  {
    XmlNode node = ((ListBoxItem)entryListBox.SelectedItem).Tag as XmlNode;
    if (node != null)
    {
      titleText.Text = node["title"].InnerText;
      urlText.Text = node["guid"].InnerText;
      dateText.Text = node["pubDate"].InnerText;
      bodyText.Text = node["description"].InnerText;
    }
  }
}

Visual Basic .NET

  Sub entryListBox_Changed(ByVal sender As Object, _
                           ByVal e As SelectionChangedEventArgs) 

    If entryListBox.SelectedIndex <> -1 Then

      Dim node As XmlNode = CType(entryListBox.SelectedItem, ListBoxItem).Tag
      If Not node Is Nothing Then

        titleText.Text = node("title").InnerText
        urlText.Text = node("guid").InnerText
        dateText.Text = node("pubDate").InnerText
        bodyText.Text = node("description").InnerText

      End If

    End If

  End Sub

ListBox が変更されると、選択した RSS フィード項目をテキスト ボックスに入力します。 これを行うには、フィードのアイテムの内部テキストを取得します。 また、 ListBoxItem を使用してノードのコピーを保持し、キャストを行って各イベント ハンドラーで取得する必要があることにも注意してください。

最後に、[ 更新] ボタンがクリックされたときに何が起こるかを処理する必要があります。

C#

void updateButton_Click(object sender, RoutedEventArgs e)
{
  if (entryListBox.SelectedIndex != -1)
  {
    XmlNode node = ((ListBoxItem)entryListBox.SelectedItem).Tag as XmlNode;
    if (node != null)
    {
      node["title"].InnerText = titleText.Text;
      node["guid"].InnerText = urlText.Text;
      node["pubDate"].InnerText = dateText.Text;
      node["description"].InnerText = bodyText.Text;

      blog.Save(BLOGURL);

      FillListBox();
    }
  }
}

Visual Basic .NET

  Sub updateButton_Click(ByVal sender As Object, _
                         ByVal e As RoutedEventArgs)

    If entryListBox.SelectedIndex <> -1 Then

      Dim node As XmlNode = CType(entryListBox.SelectedItem, ListBoxItem).Tag

      If Not node Is Nothing Then

        node("title").InnerText = titleText.Text
        node("guid").InnerText = urlText.Text
        node("pubDate").InnerText = dateText.Text
        node("description").InnerText = bodyText.Text

        blog.Save(BLOGURL)

        FillListBox()

      End If

    End If

  End Sub

ここでは、新しい情報を使用してノードを更新し、XML ドキュメントを保存し、タイトルが変更された場合に ListBox を再入力します。 これは単純な小さなアプリケーションですが、必要なコードは少し広範です。 XAML データ バインディングを使用すると、これが簡単になる可能性がありますか? はい、そうかもしれません。 XAML データ バインディングを使用した、同じプロジェクトの XAML を次に示します。

<StackPanel 
    xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
  >
  <StackPanel.Resources>
    <XmlDataProvider x:Key="RssFeed" Source="z:\adoguy.RSS" />
  </StackPanel.Resources>
  <TextBlock HorizontalAlignment="Center" 
      FontWeight="Bold">
    Blog Editor
  </TextBlock>
  <StackPanel Orientation="Horizontal" 
    HorizontalAlignment="Center">
    <ListBox Name="entryListBox" 
        Height="300" 
        ItemsSource="{Binding Source={StaticResource RssFeed}, XPath=//item}"
    >
      <ListBox.ItemTemplate>
        <DataTemplate>
          <TextBlock Text="{Binding XPath=title}" />
        </DataTemplate>
      </ListBox.ItemTemplate>
    </ListBox>
    <Grid Width="500" 
        Margin="5" 
        DataContext="{Binding ElementName=entryListBox, Path=SelectedItem}" >
      <Grid.ColumnDefinitions>
        <ColumnDefinition Width="50" />
        <ColumnDefinition Width="*" />
      </Grid.ColumnDefinitions>
      <Grid.RowDefinitions>
        <RowDefinition Height="25" />
        <RowDefinition Height="25" />
        <RowDefinition Height="25" />
        <RowDefinition Height="*" />
        <RowDefinition Height="25" />
      </Grid.RowDefinitions>
      <TextBlock Grid.Row="0" Grid.Column="0">Title:</TextBlock>
      <TextBox Grid.Row="0" Grid.Column="1" 
          Name="titleText" 
          Text="{Binding XPath=title}" />
      <TextBlock Grid.Row="1" Grid.Column="0">Url:</TextBlock>
      <TextBox Grid.Row="1" Grid.Column="1" 
          Name="urlText" 
          Text="{Binding XPath=guid}" />
      <TextBlock Grid.Row="2" Grid.Column="0">Date:</TextBlock>
      <TextBox Grid.Row="2" Grid.Column="1" 
          Name="dateText" 
          Text="{Binding XPath=pubDate}" />
      <TextBlock Grid.Row="3" Grid.Column="0">Body:</TextBlock>
      <TextBox Grid.Row="3" Grid.Column="1" 
          Name="bodyText" 
          TextWrapping="Wrap" 
          Text="{Binding XPath=description}" />
      <Button Grid.Row="4" Grid.ColumnSpan="2" Grid.Column="1" >
          Update
      </Button>
    </Grid>
  </StackPanel>
</StackPanel>

この XAML は、分離コードなしで動作します。 図 2 は、XAML のみを操作するアプリケーションを示しています (XAMLPad を使用)。

画像を大きくするにはここをクリック

図 2. XAMLPad の RSS エディター (画像をクリックすると大きな画像が表示されます)

"この機能はどのように機能しますか?" と疑問に思うかもしれません。XAML バインドを使用して作業の多くを実行しているため、機能します。 XAML の各手法については後で詳しく説明しますが、データ バインディングの一部を実行して、これが実際にどのように機能するかを説明しましょう。

まず、エディターの XML ドキュメントを読み込んで管理する XmlDataProvider オブジェクトを作成します。

<XmlDataProvider x:Key="RssFeed" Source="z:\adoguy.RSS" />

これにより、フォームに入力するために、Z: ドライブから XML ドキュメントを読み込むよう XAML に指示されます。

次に、 ListBox をバインドします。

<ListBox Name="entryListBox" 
        Height="300" 
        ItemsSource="{Binding Source={StaticResource RssFeed}, XPath=//item}"
    >

これにより、リスト ボックスに RssFeed という XAML でリソースを検索し、それをデータ ソースとして使用するように指示されます。 さらに、 XPath 式からバインドする項目のリストを取得するようにリスト ボックスに指示します (この場合、ドキュメント内のすべての項目要素)。

次に、データ テンプレートを指定して、リスト ボックスの項目に表示する内容を指定します。

<DataTemplate>
  <TextBlock Text="{Binding XPath=title}" />
</DataTemplate>

これにより 、ListBox は各項目の TextBlock オブジェクトを作成し、 XPath を使用して TextBlock に何を表示するかを決定するように指示します。

次に、すべての詳細を含むグリッドをバインドします。

<Grid Width="500" 
        Margin="5" 
        DataContext="{Binding ElementName=entryListBox, Path=SelectedItem}" >

ここでは、コンテナー (この場合は Grid) を ListBox の選択した項目にバインドするように XAML に指示しています。 外部データではなく XAML ドキュメントのコントロールにバインドするため、Source の代わりに ElementName を使用しています。 DataContext を設定することで、Grid 内のすべてのコントロールを同じオブジェクト (この場合は SelectedItem) に設定できます。

次に、各 TextBox を、必要な XML ドキュメントの部分にバインドします。

<TextBlock Grid.Row="0" Grid.Column="0">Title:</TextBlock>
      <TextBox Grid.Row="0" Grid.Column="1" 
          Name="titleText" 
          Text="{Binding XPath=title}" />
      <TextBlock Grid.Row="1" Grid.Column="0">Url:</TextBlock>
      <TextBox Grid.Row="1" Grid.Column="1" 
          Name="urlText" 
          Text="{Binding XPath=guid}" />
      <TextBlock Grid.Row="2" Grid.Column="0">Date:</TextBlock>
      <TextBox Grid.Row="2" Grid.Column="1" 
          Name="dateText" 
          Text="{Binding XPath=pubDate}" />
      <TextBlock Grid.Row="3" Grid.Column="0">Body:</TextBlock>
      <TextBox Grid.Row="3" Grid.Column="1" 
          Name="bodyText" 
          TextWrapping="Wrap" 
          Text="{Binding XPath=description}" />

DataContext は既に設定されているため、XPath 式を指定するだけで、必要な RSS フィードを取得できます。

これは、単一のガルプで飲み込もうとすることは非常に多いです。 停止し、一息つきます。 私はあなたが一気にそれを得ることを期待していません。 次のセクションでは、前の例で見たアイデアの多くをより管理しやすいものに分解しました。

XAML バインド、簡略化

Binding オブジェクトのしくみの簡単な例から始めるために、次の非常に単純な XAML ドキュメントを見てみましょう。

<Window 
    xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
  >
  <Canvas>
    <TextBox Text="This is a TextBox" />
    <TextBlock Canvas.Top="25" >Test</TextBlock>
  </Canvas>
</Window>

これにより、図 3 に示すように、2 つのコントロールを含む単純なキャンバスが作成されます。

Aa480224.wpfdatabinding_pt103(en-us,MSDN.10).gifAa480224.wpfdatabinding_pt103

図 3: 単純な XAML キャンバス

TextBlock をバインドして、テキスト ボックスのテキストを入力時に表示することができます。 これを行うには、2 つのオブジェクトを結び付けるために Binding オブジェクトが必要です。 最初に、 TextBox に名前を追加して、要素の名前で参照できるようにします。

<TextBox Name="theTextBox" />

次に、TextBlockText 要素に Binding を追加する必要があります。

<TextBlock Canvas.Top="25">
  <TextBlock.Text>    <Binding ElementName="theTextBox" Path="Text" />  </TextBlock.Text>
</TextBlock>

これにより、 TextBlockText が、ユーザーが TextBox コントロールに入力するように設定されます。

これをまとめる場合、次のコードが生成されます。

<Window 
    xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
  >
  <Canvas>
    <TextBox Name="theTextBox" Text="Hello" />
    <TextBlock Canvas.Top="25">
      <TextBlock.Text>
        <Binding ElementName="theTextBox" Path="Text" />
      </TextBlock.Text>
    </TextBlock>
  </Canvas>
</Window>

この XAML は、図 4 に示すように 、TextBox に入力するときに TextBlock を変更するフォームを作成します。

Aa480224.wpfdatabinding_pt104(en-us,MSDN.10).gifAa480224.wpfdatabinding_pt104

図 4: バインドされたコントロール

おめでとうございます。最初のバインドが完了しました。 しかし、その XML 構文は少し冗長です。 より良い書き方があるはずです。

バインドの短縮形の使用

前の例では、 Binding 要素をプロパティに追加してデータ バインディングを作成する方法を確認しました。 この簡単な例では、このようにデータ バインディングを行うのはあまり厄介ではないようです。ただし、XAML ドキュメントが増えるにつれて、この詳細な構文が煩雑になる可能性があります。 この問題を軽減するために、XAML ではバインディング構文の短縮バージョンがサポートされています。

たとえば、短縮形を使用すると、前の例は次のようになります。

<Window 
    xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
  >
  <Canvas>
    <TextBox Name="theTextBox" Text="Hello" />
    <TextBlock Canvas.Top="25"
               Text="{Binding ElementName=theTextBox, Path=Text}" />
  </Canvas>
</Window>

短縮形の構文は中かっこ ({}) で囲まれており、 Binding という単語で始まり、バインドの属性の名前と値のペアが含まれています。 短縮形構文の目的は、キーストロークが少なく読みやすくなってデータ バインディングを有効にすることです。 この記事の残りの部分では、短縮形の構文を使用します。

バインディング ソース

ここまでは、すべてのバインディング例のソースとして別のコントロールを使用しました。 ただし、ほとんどの XAML ベースのプロジェクトでは、他のコントロール以外のソースにバインドされます。 ほとんどのデータ バインディングのキーは 、Source プロパティです。 前の例では、Source プロパティを使用する代わりに、コントロールにバインドするために使用される ElementName プロパティを使用しています。 ほとんどのアプリケーションでは、XML や .NET オブジェクトなど、より重要なソースにバインドする必要があります。 XAML では、データ プロバイダー オブジェクトでこれをサポートしています。 XAML には、 ObjectDataProviderXmlDataProvider という 2 種類のデータ プロバイダーが組み込まれています。 ObjectDataProvider は.NET オブジェクトとの間のバインドに使用され、当然のことながら、XmlDataProvider は XML フラグメントとドキュメントとの間でバインドするために使用されます。 データ プロバイダーは、任意の XAML コンテナーの resources セクションで指定できます。

XmlDataProvider の使用

XmlDataProvider オブジェクトの使用例を次に示します。

<StackPanel 
    xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
  >
  <StackPanel.Resources>
    <XmlDataProvider x:Key="FavoriteColors">      <x:XData>        <Colors >          <Color>Blue</Color>           <Color>Black</Color>           <Color>Green</Color>           <Color>Red</Color>         </Colors>      </x:XData>    </XmlDataProvider>
  </StackPanel.Resources>
  <TextBlock HorizontalAlignment="Center" 
             FontWeight="Bold">
    XML Example
  </TextBlock>
  <ListBox Width="200" Height="300" 
           ItemsSource="{Binding Source={StaticResource FavoriteColors},            XPath=/Colors/Color}">
  </ListBox>
</StackPanel>

StackPanel のリソース内には、XmlDataProvider オブジェクトがあります。 x:Key は、Binding オブジェクトで参照するために使用する名前を示します。 プロバイダー内で、データ バインディングのソースとして使用する XML をインラインで作成しました。 インライン データを使用するには、コードに示すように XData 要素で囲む必要があります。 ListBoxバインドで、バインディングのソースとしてプロバイダーを指定しました。 データ ソースが XAML ドキュメントにある場合は、コードに示すように、オブジェクトが静的リソースであることを指定する必要があります。 最後に、 XPath ステートメントを使用して、 ListBox を埋めるために XML ドキュメント内のコレクションを指定します。 このコードは、図 5 に示すフォームを生成します。

Aa480224.wpfdatabinding_pt105(en-us,MSDN.10).gifAa480224.wpfdatabinding_pt105

図 5: XML データ バインディング

または、XmlDataProviderSource 属性を指定することで、プロバイダーがパスまたは URL を使用して XML のソースを検索し、同じフォームを作成するように指定することもできます。

<XmlDataProvider x:Key="FavoriteColors" 
                 Source="D:\Writing\msdn\avalondatabindingpt1\xaml\colors.xml"
/>

XmlDataProviderSource 属性は、標準 URL をポイントして、RSS などの XML API にすばやくアクセスできるようにすることもできます。

<StackPanel 
    xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
  >
  <StackPanel.Resources>
    <XmlDataProvider x:Key="MyRSS" 
      Source="http://adoguy.com/RSS"
    />
  </StackPanel.Resources>
  <TextBlock HorizontalAlignment="Center" 
             FontWeight="Bold">
    XML Example
  </TextBlock>
  <ListBox Width="500" Height="300" 
           ItemsSource="{Binding Source={StaticResource MyRSS}, 
           XPath=//item/title}">
  </ListBox>
</StackPanel>

RSS フィードに呼び出すことで、図 6 に示すように、ブログのトピックをすばやく ListBox に一覧表示するページを作成できます。

Aa480224.wpfdatabinding_pt106(en-us,MSDN.10).gifAa480224.wpfdatabinding_pt106

図 6: ブログのトピック一覧

ObjectDataProvider の使用

.NET オブジェクトへのバインドが必要な場合があります。 ここで ObjectDataProvider が使用されます。 このデータ プロバイダーを使用すると、.NET データ型のバインドを作成できます。

たとえば、次のように、.NET で単純な文字列コレクションを作成できます。

public class MyStrings : List<String>
{
  public MyStrings()
  {
    this.Add("Hello");
    this.Add("Goodbye");
    this.Add("Heya");
    this.Add("Cya");
  }
}

\- または -

Public Class MyStrings
  Inherits List(Of String)

  Public Sub New()
    Me.Add("Hello")
    Me.Add("Goodbye")
    Me.Add("Heya")
    Me.Add("Cya")
  End Sub

End Class

XAML ドキュメントの処理命令を使用して、 XMLns 宣言として名前空間を指定することで、CLR オブジェクトの名前空間全体をドキュメントのサポートされている型に追加することもできます。 たとえば、次のように名前空間のクラス全体を XAML にマップできます。

<Window 
    xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
    Title="Simple Source Binding"
    xmlns:local="clr-namespace:XamlExamples"
    x:Class="XamlExamples.SimpleSource"
 >
  <!-- ... -->
</Window>

外部アセンブリからクラスをインポートするには、 xmlns 宣言を指定できますが、アセンブリ名は次のように指定します。

<Window 
    xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
    Title="Simple Source Binding"
    xmlns:sys="clr-namespace:System,assembly=mscorlib"
    x:Class="XamlExamples.SimpleSource"
 >
  <!-- ... -->
</Window>

型をインポートしたら、 ObjectDataProvider を使用して、これらの型のいずれかからデータ ソースを指定できます。

<Window 
    xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
    Title="Simple Source Binding"
    xmlns:local="clr-namespace:XamlExamples"
    x:Class="XamlExamples.SimpleSource"
 >
  <Window.Resources>
    <ObjectDataProvider x:Key="MyStringData"                         ObjectType="{x:Type local:MyStrings}" />
  </Window.Resources>  
    <StackPanel>
      <TextBlock HorizontalAlignment="Center" 
               FontWeight="Bold">
      Simple Source Example
    </TextBlock>
    <ListBox Name="theListBox" Width="200" Height="300" 
      ItemsSource="{Binding Source={StaticResource MyStringData}}"/>
  </StackPanel>
</Window>

次のように、名前空間の名前と使用する型を持つ XAML 要素を指定して、リソースを作成することもできます。

<Window 
    xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
    Title="Simple Source Binding"
    xmlns:local="clr-namespace:XamlExamples"
    x:Class="XamlExamples.SimpleSource"
 >
  <Window.Resources>
    <local:MyStrings x:Key="MyStringData" />
  </Window.Resources>  
    <StackPanel>
      <TextBlock HorizontalAlignment="Center" 
               FontWeight="Bold">
      Simple Source Example
    </TextBlock>
    <ListBox Name="theListBox" Width="200" Height="300" 
      ItemsSource="{Binding Source={StaticResource MyStringData}}"/>
  </StackPanel>
</Window>

この構文は ObjectDataSource と同じように機能しますが、使用する方が少し簡単です。 名前空間がインポートされたので、クラスの名前 ( MyStrings など) を指定することで、データ ソース クラスを参照するリソースを追加できます。 データ バインディングは前の例と同じです。XAML コードでは、データ ソースの種類は気にせず、データ ソースであるだけであるためです。

バインド モード

ほとんどの場合、 バインディング は双方向バインディングにする必要があります。 Binding オブジェクトでは、表 1 に示すように、相違点のユース ケースをサポートするいくつかのモードがサポートされています。

表 1 サポートされているバインド モード

バインド モード 説明
TwoWay バインドされたコントロールまたはバインドのソースから、双方向の方法で変更を相互に移動します。 (これは既定のモードです)。
Oneway 変更をソースからコントロールにのみ移動します。 ソースで変更が発生すると、バインドされたコントロールのデータが変更されます。
ワンタイム データは起動時にのみバインドされ、コントロールに初めてデータが入力されると、ソースへの変更は無視されます。

次のように、マークアップにモードを含めれば、モードを指定できます。

{Binding ElementName=theTextBox, Path=Text, Mode=OneTime}

双方向バインディングのしくみを確認する 1 つの方法は、2 つのテキスト ボックスを含むキャンバスを作成することです。一方はもう一方にバインドされています。

<Window    
    xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
  >
  <Canvas>
    <TextBox Name="theTextBox" Text="Hello" />
    <TextBox Canvas.Top="25"
             Text="{Binding ElementName=theTextBox, Path=Text, Mode=TwoWay}" />
  </Canvas>
</Window>

SDK に付属する XAMLPad ツールにこのコードを貼り付けると、入力時にソース テキスト ボックスによってバインドされたテキスト ボックスが更新されますが、バインドされたコントロールからソース コントロールへの更新は、バインドされたコントロールがフォーカスを失った場合にのみ発生します。 [モード][OneWay] または [OneTime] に変更すると、これらの異なるモードによってバインドの動作方法がどのように変わるかを確認できます。

バインディング時間の制御

モードに加えて、バインドが変更をプッシュするタイミングを指定することもできます。そのためには、UpdateSourceTrigger を使用します。 UpdateSourceTrigger 型を指定することで、バインドが変更を行う時間を指定できます。

{Binding ElementName=theTextBox, Path=Text, UpdateSourceTrigger=LostFocus}

UpdateSourceTrigger プロパティは、変更でソースを更新するタイミングを指定します。 これは、 Mode=TwoWay バインド (既定値) でのみ有効です。 UpdateSourceTrigger の有効な値を表 2 に示します。

表 2 UpdateSourceTrigger 値

UpdateSourceTrigger 説明
Explicit ソースは、 BindingExpression.UpdateSource メソッドを明示的に呼び出すことによってのみ更新されます。
LostFocus バインドされたコントロールがフォーカスを失うにつれて、ソースが更新されます。
PropertyChanged 変更は、プロパティが変更されるたびにソースに更新されます。 これは既定の動作です。

DataContext の使用

この記事で取り上げる最後の概念は、 DataContext の使用方法です。 DataContext は、特定のコンテナー内のすべてのコントロールを共通オブジェクトにバインドすることを指定するために特に使用されます。

たとえば、XML ドキュメント内の特定のノードの値とテキストを表示する Canvas がある例を次に示します。

<StackPanel 
    xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
  >
  <StackPanel.Resources>
    <XmlDataProvider x:Key="FavoriteColors">
      <Colors >
        <Color ID="1">Blue</Color> 
        <Color ID="2">Black</Color> 
        <Color ID="3">Green</Color> 
        <Color ID="4">Red</Color> 
      </Colors>
    </XmlDataProvider>
  </StackPanel.Resources>
  <TextBlock HorizontalAlignment="Center" 
             FontWeight="Bold">
    XML DataContext Example
  </TextBlock>
  <Canvas DataContext="{Binding Source={StaticResource FavoriteColors},                         XPath='/Colors/Color[@ID=2]'}">
    <TextBlock Text="{Binding XPath=@ID}" />
    <TextBlock Canvas.Top="25" Text="{Binding XPath=.}" />
  </Canvas>
</StackPanel>

DataContext を XML ドキュメント (および特定の XPath 式) に設定することで、Source を含まない内のすべてのコントロールでコンテナーの DataContext を使用できることを Canvas に伝えます。 このようにして、XPath 式を指定するだけで TextBlockをバインドできます。 各 TextBlockXPath 式は、相対 XPath 式であることに注意してください。 これは、オブジェクト バインディングでも同じになります。

<Window 
    xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
    Title="Simple Source Binding"
    x:Class="XamlExamples.SimpleSource"
  >
  <Window.Resources>
    <ObjectDataProvider TypeName="XamlExamples.MyStrings, XamlExamples"
                        x:Key="MyStringData" />
  </Window.Resources>  
    <StackPanel>
      <TextBlock HorizontalAlignment="Center" 
               FontWeight="Bold">
      Object DataContext Example
    </TextBlock>
    <Canvas DataContext="{Binding Source={StaticResource MyStringData}}">
      <TextBlock Text="{Binding Path=Length}" />
      <TextBlock Canvas.Top="25" Text="{Binding Path=Item[0]}" />
    </Canvas>
  </StackPanel>
</Window>

XML の代わりにオブジェクトを使用することは、単に XPath 式ではなく Path 式を使用することを意味します。

ここはどこですか。

短いバージョンと長いバージョンの両方で、 Binding オブジェクトを使用して XAML でデータ バインディングを直接実行する方法について説明しました。 XML またはオブジェクト データ プロバイダーを利用することで、アプリケーション内のさまざまな種類のオブジェクトにバインドできます。 また、Binding オブジェクトの ElementName 構文を使用して、他のコントロールにバインドする方法についても説明しました。 このシリーズの次の部分では、独自のオブジェクトまたは .NET データ コンテナー ( DataSourcesDataSets など) を使用して、この情報を取得し、実際のデータベース データにバインドする方法について説明します。

リファレンス

  • WinFX SDK
  • Chris Sells と Ian Griffith によるWindows Presentation Foundationのプログラミング