じょいのーと

プログラミング関連のアレコレを書いています

MultiBindingの使い方と使いどころ

MultiBindingは複数Sourceと一つのTargetをバインディングするクラスです。
便利なんですが、あまりWeb上に日本語情報がないので健忘録を兼ねて書いてみます。

通常のBindingとの違いは、主に3点。

1. 複数のBindingSourceを指定可能

Multiというからには当然ですが、何個でも指定できます。通常のBinding複数個を束ねるようなイメージをすれば大体は合ってます。

2. 複数Sourceの変更通知をトリガーに動作する

1にも書きましたが、通常のBindingを束ねたようなクラスなので、束ねられたN個のBindingが1つでも反応した時点でMultiBindingSourceによるTargetの更新(あるいは逆)が行われます。

3. MultiValueConverterの指定が必須

複数のSourceをどういう形でTargetに反映させますか? という部分を書く必要があります。
通常のBindingの場合、BindingSourceとTargetが1対1なので単純な型変換と代入で済みますが、Sourceが複数の場合は"標準の動き"というものを定義できないので、IMultiValueConverterインターフェイスを実装したオブジェクトを指定する必要があります。(※しないと例外が発生します)

MultiBindingの記法

まずは書き方です。
VS2013の時点で、MultiBindingは入力補完に出てくるパターンがない(と思う)ので不安になりますが、書けば動きます。

通常のBindingはXAMLで以下のように書きます。

<!-- TargetTextプロパティとTextBlock.Textプロパティの値をBinding -->
<TextBlock Text="{Binding SourceText}"/>

<!-- あるいは、省略ナシで書くと以下 -->
<TextBlock>
    <TextBlock.Text>
        <Binding Path="SourceText"/>
    </TextBlock.Text>
</TextBlock>

MultiBindingだとXAMLで以下のように書きます。

<TextBlock>
    <TextBlock.Text>
        <MultiBinding Converter="{StaticResource xxxConverter}">
            <Binding Path="SourceText1"/>
            <Binding Path="SourceText2"/>
        </MultiBinding>
    </TextBlock.Text>
</TextBlock>

MultiValueConverterの実装例

すごいざっくりした例を出すと、以下のような感じがイメージつかみやすいかと思います。

実装方法
public class xxxConverter : IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        return values.Aggregate((lhs, rhs) => String.Format("{0}:{1}", lhs, rhs));
    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
    {
        return value.ToString().Split(':');
    }
}

object配列に入ってる順はXAMLの記述順なので、取扱注意。
想定と違う値を入れるとすぐ落ちますが、動作イメージ優先で。

使用方法
<Window.Resources>
    <converter:xxxConverter x:Key="xxxConverter" />
</Window.Resources>
<StackPanel>
    <TextBox>
        <TextBox.Text>
            <MultiBinding Converter="{StaticResource xxxConverter}" UpdateSourceTrigger="PropertyChanged">
                <Binding Path="A" />
                <Binding Path="B" />
                <Binding Path="C" />
            </MultiBinding>
        </TextBox.Text>
    </TextBox>
    <TextBox Text="{Binding A, UpdateSourceTrigger=PropertyChanged}" />
    <TextBox Text="{Binding B, UpdateSourceTrigger=PropertyChanged}" />
    <TextBox Text="{Binding C, UpdateSourceTrigger=PropertyChanged}" />
</StackPanel>

A,B,CはDataContextに設定されているクラスのプロパティ(string型)だと思って読んでください。
こんな感じのものを動かすと、MultiValueの相互Bindingがどういう事をやっているかのイメージが付きやすいと思います。

普段はあまり使いませんが、2つの情報ソースの合成結果を表示したい場合に便利です。