データバインディングを使ってUIとUIを結びつける その２ BooleanToVisibilityConverter編

トグルボタンを使ってUIの表示状態を切り替えてみる。
大体のUIは`Visibility`というプロパティで管理されている。
`Visible`, `Collapsed`の二つの状態を取る。

一方でトグルボタンをクリックすると`IsChecked`というプロパティの状態が`True`, `False`[^1]と切り替わるのだが、
これをそのまま`x:Bind`しようとするとコンパイラに怒られる。

```xml:MainPage.Xaml
<Page
    ...
    mc:Ignorable="d">

    <StackPanel Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <TextBlock Visibility="{x:Bind toggleButton.IsChecked, Mode=OneWay}" HorizontalAlignment="Center" FontSize="32" Text="Show"/>
        <ToggleButton x:Name="toggleButton" Content="Change" FontSize="32" HorizontalAlignment="Center" />
    </StackPanel>
</Page>
```

![error.gif](https://qiita-image-store.s3.amazonaws.com/0/115898/94232d97-5398-2ffc-3989-2a7bdd4b36d2.gif "VisualStudioさんぉこの様子")

型が違うので当然だがこのままでは困るので、それを変換してくれるコンバーターを登録する。

まずはこのクラスをプロジェクトに追加する。
これがコンバーターだ。

```csharp:boolean2visibilityconverter.cs
using System;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Data;

namespace BindToCollectionData
{
    /// <summary>
    /// BooleanをVisibilityに変換する。
    /// </summary>
    public class Boolean2VisibilityConverter : IValueConverter
    {
        /// <summary>
        /// Trueをセットした場合、変換を逆転させる。TrueがCollapsedを返す。
        /// </summary>
        public bool IsReversed { get; set; }

        public object Convert(object value, Type typeName, object parameter, string language)
        {
            var val = System.Convert.ToBoolean(value);
            if (this.IsReversed)
            {
                val = !val;
            }
            if (val)
            {
                return Visibility.Visible;
            }
            return Visibility.Collapsed;
        }
        public object ConvertBack(object value, Type typeName, object parameter, string language)
        {
            throw new NotImplementedException();
        }
    }
}
```

コンバーターは`IValueConverter`インターフェースを継承し、
`Convert`と`ConvertBack`を実装してあげればいいようだ。
よくわからないので変換部分だけ修正していけばいいだろう。

そして`App.xaml`ファイルに修正を加える。`<Application.Resources>`以下が追加されている。

```xml:App.xaml

<Application
    x:Class="BindToCollectionData.App"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:BindToCollectionData"
    RequestedTheme="Dark">

    <Application.Resources>
        <local:Boolean2VisibilityConverter x:Key="True2Visibility" IsReversed="False"/>
        <local:Boolean2VisibilityConverter x:Key="False2Visibility" IsReversed="True"/>
    </Application.Resources>

</Application>

```

`Boolean2VisibilityConverter`に`x:Key`を割り当ててやることでこの名前で利用できるようになる。
`public`なフィールドやプロパティがある場合は
`IsReversed="True"`のように指定してコンバーターの動作状態を変更したりできる。

もしもコンバーターを`Common`フォルダなどにまとめていた場合（今回はプロジェクト名`MyProject`として）`Application`タグに
`xmlns:hogehoge="MyProject.Common"`のように**XML名前空間**[^2]を宣言し、
`<hogehoge:Boolean2VisibilityConverter x:Key="...`と宣言しないといけないようだ。

そして`x:Bind`だ。`Converter={StaticResource True2Visibility},`という記述を追加している。

```xml:MainPage.xaml

<Page
    x:Class="BindToCollectionData.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:BindToCollectionData"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">

    <StackPanel Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <TextBlock Text="Show" Visibility="{x:Bind toggleButton.IsChecked, Converter={StaticResource True2Visibility}, Mode=OneWay}" HorizontalAlignment="Center" FontSize="32" />
        <ToggleButton x:Name="toggleButton" Content="Change" FontSize="32" HorizontalAlignment="Center" />
    </StackPanel>
</Page>
```

これを実行して、ボタンを押すとこんな風にボタンの状態に合わせてUIの表示状態が切り替わる。

![hidden.gif](https://qiita-image-store.s3.amazonaws.com/0/115898/372c27dd-cc5a-4ac7-cd31-55c003c0b895.gif)

![show.gif](https://qiita-image-store.s3.amazonaws.com/0/115898/e0e68647-88d0-0a0e-b621-694ad10581d4.gif)

少し応用してハンバーガーボタン(`ToggleButton`を使ったもの)と`SplitView`を組み合わせればメニューを開閉するアプリが作れるようになる。[^3]

---
どうもWindows8の頃は`Common`フォルダ[^4]内に`BooleanToVisibilityConverter.cs`というズバリそのものが存在していたようだが、今はないらしい。
> **Windows 8.1のストアアプリのテンプレートの構造**
> http://blog.okazuki.jp/entry/2013/09/21/224812

---


参考:**A BooleanToVisibilityConverter for WinRT**
http://blogs.u2u.be/diederik/post/2011/11/14/null.aspx
Thank you Diederik.

**データ バインディングの概要**
https://msdn.microsoft.com/ja-jp/library/windows/apps/xaml/mt269383.aspx

---

[^1]: 正確にはTrue, False, nullの三つの状態を取る`Nullable<Boolean>`型(`boolean`型ではない)というよくわからないもののようだ。
[^2]: https://msdn.microsoft.com/ja-jp/library/windows/apps/xaml/mt185594.aspx

[^3]: あとでハンバーガーボタンの例を作って置きたい。
[^4]: ストアアプリテンプレートを使って作成を開始した場合、`Common`フォルダ内には便利グッズ、もといヘルパークラスやコンバーターが入っていたようだ。なんでUWPのテンプレートにはないの…？