エクスポート (0) 印刷
すべて展開
情報
要求されたトピックは次のとおりです。しかし、このトピックはこのライブラリには含まれていません。

Windows Phone 8 のデータ バインディング

2014/06/18

対象: Windows Phone 8 および Windows Phone Silverlight 8.1 | Windows Phone OS 7.1

データ バインディングは、Windows Phone アプリがデータを表示し、データと対話するための簡単な方法を提供します。データの表示方法は、データの管理とは分離されています。UI とデータ オブジェクトの間の接続 (バインド) を確立すると、データが UI とデータ オブジェクトの間を移動できるようになります。バインディングが確立され、データが変更されると、データにバインドされている UI 要素にその変更が自動的に反映されます。同様に、ユーザーが UI 要素で行った変更を、データ オブジェクトに反映できます。たとえば、ユーザーが TextBox の値を編集した場合、基になるデータの値が自動的に更新されてその変更が反映されます。

一般的なバインディング シナリオとして、ヘッドラインの一覧への ListBox のバインド、顧客データ オブジェクトへの入力フォームの TextBox のバインド、現在のユーザーの写真への Image のバインドなどがあります。

このトピックでは、単純なコード例を使用してデータ バインディングの概念について説明します。多くのデータ バインディング タスクは、Visual Studio を使用して実行することもできます。

このトピックは、次のセクションで構成されています。

バインディングを確立するには、ソースとターゲットを必ず指定する必要があります。次の図に、バインディングの基本概念を示します。

Explain Binding Details

ソースは、ターゲット要素自体または他の UI 要素を含めた、任意の CLR オブジェクトです。ターゲットがデータ テンプレートに含まれる場合は、テンプレートが適用される UI 要素をソースとして使用できます。

ターゲットとしては、FrameworkElement の任意の DependencyProperty を使用できます。

次の場合、ターゲットとして DependencyObjectDependencyProperty も使用できます。

Windows Phone 8 を起動すると、次の場合、ターゲットとして Style 内の SetterValue プロパティも使用できます。例については、Style クラスの概要を参照してください。

バインディング エンジンは、次の要素に関する情報を Binding オブジェクトから取得します。

  • ソースとターゲットのオブジェクト。

  • データ フローの方向。Binding.Mode プロパティを設定して、方向を指定します。

  • 存在する場合は値コンバーター。値コンバーターは、Binding.Converter プロパティを IValueConverter を実装するクラスのインスタンスに設定することで指定します。

  • StringFormatFallbackValueTargetNullValue などのその他の設定。プロパティの完全な一覧については、Binding クラスを参照してください。

たとえば、TextBoxForeground プロパティを SolidColorBrush にバインドして、データに基づいてテキストの色を変更できます。このシナリオでは、Foreground プロパティがバインディングのターゲット、SolidColorBrush オブジェクトがソースです。

次の例は、TextBoxForeground 色を SolidColorBrush にバインドする方法をコードおよび XAML で示しています。バインディング ソースは、このトピックで後述する MyColors クラスのプロパティの 1 つです。


<TextBox x:Name="MyTextBox" Text="Text" Foreground="{Binding Brush1, Mode=OneWay}"/>



// Create an instance of the MyColors class 
// that implements INotifyPropertyChanged.
MyColors textcolor = new MyColors();

// Brush1 is set to be a SolidColorBrush with the value Red.
textcolor.Brush1 = new SolidColorBrush(Colors.Red);

// Set the DataContext of the TextBox MyTextBox.
MyTextBox.DataContext = textcolor;


メモメモ:

この例では、バインディングの作成に XAML 属性構文を使用しています。XAML でバインディングを作成するには、オブジェクト要素構文を使用することもできます。詳細については、「Windows Phone 8 の XAML」を参照してください。

バインディングは、XAML で {Binding ...} 構文を使用して作成します。TextBoxDataContext プロパティを設定して、ソースをコードに設定します。

データ コンテキストは継承されます。データ コンテキストを親要素に設定すると、その子もすべて同じデータ コンテキストを使用します。バインディング オブジェクトの Source プロパティを設定するか、またはそのすべての子に適用される DataContext を設定すると、子要素はこの動作をオーバーライドできます。

データ コンテキストの設定は、同じソースを使用する複数のバインディングが必要な場合に便利です。単一バインディングのソースを設定するには、Binding オブジェクトの Source プロパティを設定します。詳細については、「Windows Phone のデータ バインディングを作成する方法」を参照してください。

ElementName プロパティまたは RelativeSource プロパティを使用してバインディング ソースを指定することもできます。ElementName プロパティは、アプリ内の他の要素にバインドする場合 (スライダーを使用してボタンの幅を調整する場合など) に役立ちます。RelativeSource プロパティは、ControlTemplate または Style でバインディングを指定する場合に役立ちます。

Binding.Path プロパティを設定して、ソース オブジェクトのプロパティにバインドできます。Path プロパティは、入れ子になったプロパティ、添付プロパティ、および文字列インデクサーにバインドするためのさまざまな構文オプションをサポートしています。

つまり、前の例のバインディング エンジンでは、TextBoxForeground プロパティを TextColor オブジェクトの brush1 プロパティに関連付けて、バインディング (既定では OneWay) を作成しています。

各バインディングには、データ フローの方法とタイミングを決定する Mode プロパティがあります。Windows Phone では、3 種類のバインディングを使用できます。

  • OneTime バインディングは、バインディングの作成時にソース データでターゲットを更新します。

  • OneWay バインディングは、バインディングの作成時とデータの変更のたびにソース データでターゲットを更新します。これは、既定のモードです。

  • TwoWay バインディングは、ターゲットまたはソースが変更されたときにターゲットとソースの両方を更新します。または、ソースの自動更新を無効にして、選択したときにだけソースを更新することもできます。

ターゲットの自動更新を実行するには、次のセクションで説明するように、ソース オブジェクトで INotifyPropertyChanged インターフェイスを実装する必要があります。

ソース オブジェクトに加えた変更をターゲットに反映させるには、ソースで INotifyPropertyChanged インターフェイスを実装する必要があります。INotifyPropertyChanged には PropertyChanged イベントがあり、ソースが変更されたことをバインディング エンジンに通知するので、バインディング エンジンはターゲット値を更新できます。

次の例では、MyColors クラスが OneWay バインディングのための INotifyPropertyChanged インターフェイスを実装します。


// Create a class that implements INotifyPropertyChanged.
public class MyColors : INotifyPropertyChanged
{
    private SolidColorBrush _Brush1;

    // Declare the PropertyChanged event.
    public event PropertyChangedEventHandler PropertyChanged;

    // Create the property that will be the source of the binding.
    public SolidColorBrush Brush1
    {
        get { return _Brush1; }
        set
        {
            _Brush1 = value;
            // Call NotifyPropertyChanged when the source property 
            // is updated.
            NotifyPropertyChanged("Brush1");
        }
    }


    // NotifyPropertyChanged will raise the PropertyChanged event, 
    // passing the source property that is being updated.
    public void NotifyPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, 
                new PropertyChangedEventArgs(propertyName));
        }
    }
}


ItemsControl にバインドされているコレクションの変更通知を取得するには、INotifyPropertyChanged に加えて INotifyCollectionChanged を実装します。INotifyCollectionChanged を実装した場合、コレクションに加えられた変更 (たとえばオブジェクトの追加、削除) は、ターゲットに反映されます。コレクション内のオブジェクトのプロパティ変更通知を取得するには、オブジェクトで INotifyPropertyChanged を実装する必要があります。

独自のコレクション クラスを実装する前に、INotifyCollectionChanged および INotifyPropertyChanged の組み込み実装を含む ObservableCollection<T> クラスの使用を検討してください。

TwoWay バインディングでは、TextBoxText プロパティへのバインディングを除き、ターゲットが変更されるとソースが自動的に更新されます。この場合は、TextBox がフォーカスを失ったときに更新が行われます。

ソースの自動更新を無効にして、選択したときにソースを更新することができます。この方法は、たとえば、バインドされたデータ ソースを更新する前に複数のコントロールからのユーザー入力を検証する場合などに使用できます。

ソースの自動更新を無効にするには、UpdateSourceTrigger プロパティを Explicit に設定します。この設定は、同じ Binding オブジェクトを使用する (継承されたデータ コンテキストを使用している場合など) すべてのバインディングに適用されます。ただし、各バインディングのソースを個別に更新する必要があります。バインディングを更新するには、最初にターゲット要素の FrameworkElement.GetBindingExpression メソッドを呼び出して、ターゲットの DependencyProperty を渡します。次に、その戻り値を使用して、BindingExpression.UpdateSource メソッドを呼び出します。この処理のコード例を次に示します。


<TextBox x:Name="textBox1" Text="{Binding Test, Mode=TwoWay, UpdateSourceTrigger=Explicit}" />
<Button Content="Update" Click="Button_Click" />



public class TestData
{
    public String Test { get; set; }
}

TestData data;

public MainPage()
{
    InitializeComponent();
    data = new TestData { Test = "one" };
    textBox1.DataContext = data;
}

private void Button_Click(object sender, RoutedEventArgs e)
{
    BindingExpression expression = textBox1.GetBindingExpression(TextBox.TextProperty);
    MessageBox.Show("Before UpdateSource, Test = " + data.Test);
    expression.UpdateSource();
    MessageBox.Show("After UpdateSource, Test = " + data.Test);
}


バインディング ソース オブジェクトは、プロパティにデータが含まれる単一のオブジェクト、またはオブジェクトのコレクションとして処理できます。たとえば、毎月のクレジット カード請求書などの項目一覧を表示する場合が考えられます。これを行うには、ItemsControl を使用し、DataTemplate を使用してコレクション内の各項目を表示します。


<Grid.Resources>
  <DataTemplate x:Name="dataTemplate">
    <Grid>
      <Grid.ColumnDefinitions>
        <ColumnDefinition />
        <ColumnDefinition />
      </Grid.ColumnDefinitions>

      <TextBlock Grid.Column="0" 
          Text="{Binding Month, Converter={StaticResource Converter1}}"/>
      <TextBlock Grid.Column="1" Text="{Binding Total}"/>    
    </Grid>
  </DataTemplate>
</Grid.Resources>

<ItemsControl x:Name="IC1" ItemsSource="{Binding}" 
  ItemTemplate="{StaticResource dataTemplate}"/>


IEnumerable を実装するすべてのコレクションを列挙できます。コレクションが変更されたときにターゲットが ItemsSource を更新するように設定するには、INotifyCollectionChanged を実装します。変更通知の詳細については、このトピックの前の「変更通知」を参照してください。

他のデータ ソースに対する並べ替え、グループ化、フィルター処理、および通貨のサポートを提供する、CollectionViewSource クラスのインスタンスにバインドすることもできます。CollectionViewSource により、ユーザーの選択内容の変更と同期状態が維持されるデータの複数のビューを表示できます。

CollectionViewSource を使用すると、階層的に関連性のあるデータに複数のコントロールをバインドすることもできます。

コントロールをバインドできるようにオブジェクトのジェネリック リストをカプセル化する方法については、List<T> および Dictionary<TKey, TValue> の最初のコード例を参照してください。

Windows Phone では、ターゲットからソースへの更新用の TwoWay バインディングで簡単なデータ検証をサポートしています。

Windows Phone では、バインディングの Validation.Errors 添付プロパティにエラーが含まれている場合は、必ず検証エラーを報告します。エラーは、次の場合にこのコレクションに追加されます。

  • 例外がバインディング エンジンの型コンバーターからスローされた。

  • 例外がバインディング オブジェクトの set アクセサーからスローされた。

  • 例外がデータ オブジェクトまたはメンバーに適用される検証属性からスローされた。

  • バインディング オブジェクトには IDataErrorInfo が実装され、その Item プロパティによって null または Empty 以外の値が返される。

  • バインディング オブジェクトには INotifyDataErrorInfo が実装され、その GetErrors メソッドによって null 以外の値が返される。GetErrors の戻り値は、非同期の検証操作が完了したことを受けて変化する場合があります。

Windows Phone では、次の場合に検証エラーの視覚的フィードバックが表示されます。

視覚的フィードバックには、エラーを含むコントロールが示され、近くにエラー メッセージが表示されます。

検証エラーの発生または解決に関する通知を受け取るには、バインディング オブジェクトの NotifyOnValidationError プロパティを true に設定する必要があります。この設定を使用することで、バインディング エンジンに対し、検証エラーが Validation.Errors コレクションに追加されたときまたはこのコレクションから削除されたときに、BindingValidationError イベントを生成するように指示できます。たとえば、エラー イベントを処理して、エラーをログに記録したり、視覚的フィードバックを追加したりできます。

BindingValidationError イベントを処理するには、ターゲット オブジェクトまたはその親にイベント ハンドラーを作成します。BindingValidationError イベントはルーティング イベントなので、イベントを生成した要素で処理しないと、そのイベントは処理されるまで伝達され続けます。ルーティング イベントの詳細については、「Windows Phone 8 のイベント」を参照してください。

次の例で、カスタム バインディングを検証する方法を示します。

バインディングは XAML で作成します。


<StackPanel BindingValidationError="StackPanel_BindingValidationError" >
    <StackPanel.Resources>
        <my:Bills x:Name="MyBills"/>
    </StackPanel.Resources>

    <TextBlock 
        TextWrapping="Wrap"
        Text="To generate a validation error, input a negative number or a non-number and then tap the button."
    />

    <TextBox x:Name="MyTextBox" Width="50" Margin="10">
        <TextBox.Text>
            <Binding Mode="TwoWay" Source="{StaticResource MyBills}" 
                 Path="Amount" NotifyOnValidationError="true" 
                 ValidatesOnExceptions="true"/>
        </TextBox.Text>
    </TextBox>
    <Button Content="Tap to Update"/>
</StackPanel>


値が負の場合は、set アクセサーでソース オブジェクトが例外をスローします。


public class Bills
{
    private double _Amount;
    public double Amount
    {
        get { return _Amount; }
        set
        {
            if (value < 0)
                throw new Exception("Amount must be greater than zero.");
            _Amount = value;
        }
    }

}


StackPanelBindingValidationError イベントのハンドラーを実装します。


private void StackPanel_BindingValidationError(object sender, 
    ValidationErrorEventArgs e)
{
    if (e.Action == ValidationErrorEventAction.Added)
    {
        MyTextBox.Background = new SolidColorBrush(Colors.Red);

    }
    else if (e.Action == ValidationErrorEventAction.Removed)
    {
        MyTextBox.Background = new SolidColorBrush(Colors.White);
    }
}


このコード例では、数字ではなく文字を入力して型コンバーターで発生したエラーを取得します。ソース オブジェクトの set アクセサーからのエラーを取得するには、負の数を入力します。検証エラーを解決するには、正の数を入力します。TextBox ターゲットからソースへの更新は、TextBox がフォーカスを失った場合にのみ発生します。フォーカスを変更するためのボタンが用意されています。必要であれば、「データ ソースの更新」で説明したように、ボタンのクリックに応答してソースを手動で更新できます。

データを、格納されている形式とは異なる形式で表示することが必要になる場合もあります。次にいくつかの例を示します。

  • RGBA 値として格納した色を文字列名で表示する場合。

  • 浮動小数点値として格納した数を通貨値で表示する場合。

  • DateTime として格納した日付をカレンダーに表示する場合。

  • null 値を格納したが、わかりやすい既定値を表示する場合。

StringFormat プロパティを設定すると、表示される String 値の書式を指定できます。

TargetNullValue プロパティを設定することによって、値が null の場合に、わかりやすい既定値を表示することもできます。

また、どのバインディングにもコンバーターを設定できます。コンバーターは、クラスを作成して IValueConverter インターフェイスを実装することにより、シナリオごとにカスタマイズします。IValueConverter を実装する方法を次の例に示します。


// Custom class implements the IValueConverter interface.
public class DateToStringConverter : IValueConverter
{

    #region IValueConverter Members

    // Define the Convert method to change a DateTime object to 
    // a month string.
    public object Convert(object value, Type targetType, 
        object parameter, 
System.Globalization.CultureInfo culture)
    {
        // value is the data from the source object.
        DateTime thisdate = (DateTime)value;
        int monthnum = thisdate.Month;
        string month;
        switch (monthnum)
        {
            case 1:
                month = "January";
                break;
            case 2:
                month = "February";
                break;
            default:
                month = "Month not found";
                break;
        }
        // Return the value to pass to the target.
        return month;

    }

    // ConvertBack is not implemented for a OneWay binding.
    public object ConvertBack(object value, Type targetType, 
        object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }

    #endregion
}


バインディングの Converter パラメーターを定義した場合、Convert メソッドと ConvertBack メソッドがバインディング エンジンによって呼び出されます。ソースからデータが渡されると、バインディング エンジンは、Convert を呼び出し、返すデータをターゲットに渡します。ターゲットからデータが渡されると、バインディング エンジンは、ConvertBack を呼び出し、返すデータをソースに渡します。Converter パラメーターを設定する方法を次の例に示します。


<phone:PhoneApplicationPage.Resources>
  <local:DateToStringConverter x:Key="Converter1"/>
</phone:PhoneApplicationPage.Resources>


...


<TextBlock Grid.Column="0" 
    Text="{Binding Month, Converter={StaticResource Converter1}}"/>


コンバーターには省略可能なパラメーターもあります。変換で使用するカルチャを指定できる ConverterCulture、および変換ロジックに渡すパラメーターを指定できる ConverterParameter です。これらのパラメーターの使用例については、「IValueConverter」を参照してください。

変換でエラーが発生した場合は、例外をスローしないでください。代わりに DependencyProperty.UnsetValue を返します。これにより、データ転送が中止されます。

バインディング ソースを解決できない場合に必ず表示される既定値を表示するには、FallbackValue プロパティを設定します。これは、変換エラーおよび書式エラーを処理する場合に便利です。また、バインドされたコレクション内のすべてのオブジェクトに存在するとは限らないソース プロパティにバインドする場合にも便利です。

表示:
© 2015 Microsoft