【備忘録】マルチバインディングについて

## 初めに
WPFのViewを作り込むとき、Blazorや.net MVC、JavaScript の様に
ViewModelのデータに対して表示側だけで
集計したり、文字を結合して表示したいときがありませんか？
それが、マルチバインディングを使うことでこれらが可能となります。

今回は、そのマルチバインディングについてのメモです。

## マルチバインディングとは何か
通常のバインディングは、一つの値を一つのプロパティにバインドします。
でも、例えば次のような場合にはどうでしょう？


**複数の入力（例えば、名前と苗字）を結合して一つのラベルに表示したい。**
**数値が2つあり、それを足した合計を画面に表示したい。**

こういった場合に活躍するのが「マルチバインディング」です。
複数のバインディングソースを結合したり加工する機能として便利です。


マルチバインディングを使うためには、次の要素を使います。
**１．\<MultiBinding>タグ**
マルチバインディングを定義するタグです。

**２．バインディングのリスト (\<Binding>)**
マルチバインディングの中に、実際のバインディングをリストとして記述します。

**３．Converter（コンバーター）**
複数の値をどのように結合するかを指定するクラス（カスタムロジック）。
	
何も考えず、MultiBindingタグを使用すれば結合できるものではありません。
コンバーターというカスタムロジックを作り、そこにデータ渡して結合させ
表示箇所に戻して表示しています。
その為、コンバーターを作成するは必須となります。
	
## 実際のコード
例として、名前と苗字を結合するViewを作成します。
```html
<Window x:Class="MultiBindingExample.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:MultiBindingExample"
        Title="MultiBinding Example" Height="200" Width="400">
    <Window.Resources>
        <!-- コンバーターをリソースとして登録 -->
        <local:FullNameConverter x:Key="FullNameConverter" />
    </Window.Resources>
    <StackPanel>
        <!-- TextBoxで「名前」と「苗字」を入力 -->
        <TextBox Name="FirstNameBox" Width="200" Margin="5" />
        <TextBox Name="LastNameBox" Width="200" Margin="5" />
        
        <!-- ラベルにMultiBindingで結合結果を表示 -->
        <TextBlock Width="300" Height="30" Margin="5">
            <TextBlock.Text>
                <MultiBinding Converter="{StaticResource FullNameConverter}">
                    <Binding ElementName="FirstNameBox" Path="Text" />
                    <Binding ElementName="LastNameBox" Path="Text" />
                </MultiBinding>
            </TextBlock.Text>
        </TextBlock>
    </StackPanel>
</Window>
```
ここで重要なのは、
* **FullNameConverter**をリソースとして登録する事
*  **MultiBinding**タグに使用するコンバーターと使用するデータをバインディングで渡すことです。

次に、**FullNameConverter**を作成します。

```FullNameConverter.cs
using System;
using System.Globalization;
using System.Windows.Data;

namespace MultiBindingExample
{
    public class FullNameConverter : IMultiValueConverter
    {
        // 結合ロジックをここに記述
        public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
        {
            string firstName = values[0]?.ToString() ?? string.Empty;
            string lastName = values[1]?.ToString() ?? string.Empty;

            // 名前 + 苗字を結合
            return $"{lastName} {firstName}";
        }

        public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
        {
            // ConvertBackは今回使わないので未実装
            throw new NotImplementedException();
        }
    }
}
```
valuesは、XAMLのBindingで渡したデータが配列として格納されています。
配列の順番は、Bindingの記述順で決まります。
今回だとvalues[0]にFirstNameBox、values[1]にLastNameBoxが格納されています。

コンバーターの注意点として、
* IMultiValueConverter インターフェースを実装する際に、Convert メソッドと ConvertBack メソッドを定義する必要があります。
* 今回の例では「結果を画面から逆変換してデータに戻す必要がない」ため、ConvertBack メソッドでは単に NotImplementedException をスローしています。

これにより、簡単な名前と苗字を入力すると結合して表示される表示ができました。

## 最後に
今回例として、文字列の結合でしたが
コンバーターの中身によっては、一定の数値を超えたら色を変えたり、複数のチェックボックスから表示する内容を変更したりと、データいじらずに表示を変えることが出来るため、データ周りのバグを抑えることもできます。
以上、マルチバインディングのメモでした。