文字列以外の値をコントロールにバインドするには?[Win 8/WP 8]WinRT/Metro TIPS

Windowsストア・アプリやWindows Phone 8アプリで文字列以外の値をコントロールにデータ・バインドする方法を、DateTimeOffset型とbool型を例に解説する。

» 2013年04月11日 06時45分 公開
[山本康彦BluewaterSoft]
WinRT/Metro TIPS
業務アプリInsider/Insider.NET

powered by Insider.NET

「WinRT/Metro TIPS」のインデックス

連載目次

  前回は文字列をコントロールにデータ・バインドする方法を解説した。では、文字列以外の値をデータ・バインドするにはどうしたらよいだろう?

 本稿では、DateTimeOffset型とbool型(VBではBoolean型)を例としてその方法を解説する。なお、掲載しているコードは特に記載のない限り、Windowsストア・アプリとWindows Phone 8で同じである。本稿のサンプルは「Windows Store app samples:MetroTips #32(Windows 8版)」と「Windows Store app samples:MetroTips #32(WP 8版)」からダウンロードできる。

事前準備

 Windows 8(以降、Win 8)向けのWindowsストア・アプリを開発するには、Win 8とVisual Studio 2012(以降、VS 2012)が必要である。これらを準備するには、第1回のTIPSを参考にしてほしい。本稿では64bit版Win 8 ProとVS 2012 Express for Windows 8を使用している。

 Windows Phone 8向けのアプリを開発するには、SLAT対応CPUを搭載したPC上の64bit版Win 8 Pro以上Windows Phone SDK 8.0(無償)が必要となる。

文字列と同じようにしてDateTimeOffset型をデータ・バインドしてみる

 前回は簡易的な「デジタル時計」クラスを作り、string型の「NowTime」プロパティを公開し、それをテキスト・ブロックのTextプロパティにバインドした。この「NowTime」プロパティを、今回はDateTimeOffset型に変えてみよう。すると、「デジタル時計」クラス(=Clockクラス)は次のコードのようになる。

public class Clock : INotifyPropertyChanged
{
  // 現在時刻を表すプロパティ ※今回はDateTimeOffset型
  public DateTimeOffset NowTime { get; private set; }

  // NowTimeプロパティが変化したときに発生させるイベントの定義
  public event PropertyChangedEventHandler PropertyChanged;

  public Clock()
  {
    Run(); // 時刻監視の無限ループを動かす
  }

  private async void Run()
  {
    DateTimeOffset lastTime;
    while (true)
    {
      await Task.Delay(10); // おおよそ10ミリ秒ごとにシステム時計をチェックする
      var nowTime = DateTimeOffset.Now;
      if (lastTime.Second != nowTime.Second)
      {
        // 秒が変わったら、プロパティに時刻をセットし、イベントを発火させる
        this.NowTime = nowTime;
        if (this.PropertyChanged != null)
          this.PropertyChanged(this, new PropertyChangedEventArgs("NowTime"));

        lastTime = nowTime;
      }
    }
  }
}

Public Class Clock
  Implements INotifyPropertyChanged

  ' 現在時刻を表すプロパティ ※今回はDateTimeOffset型
  Private _nowTime As DateTimeOffset
  Public Property NowTime As DateTimeOffset
    Get
      Return _nowTime
    End Get
    Private Set(value As DateTimeOffset)
      _nowTime = value
    End Set
  End Property

  ' NowTimeプロパティが変化したときに発生させるイベントの定義
  Public Event PropertyChanged(sender As Object, e As PropertyChangedEventArgs) _
                  Implements INotifyPropertyChanged.PropertyChanged

  Public Sub New()
    Run() ' 時刻監視の無限ループを動かす
  End Sub

  Private Async Sub Run()
    Dim lastTime As DateTimeOffset
    While (True)
      Await Task.Delay(10)  ' おおよそ10ミリ秒ごとにシステム時計をチェックする
      Dim nowTime = DateTimeOffset.Now
      If (lastTime.Second <> nowTime.Second) Then
        ' 秒が変わったら、プロパティに時刻をセットし、イベントを発火させる
        Me.NowTime = nowTime
        RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs("NowTime"))

        lastTime = nowTime
      End If
    End While
  End Sub
End Class

「デジタル時計」クラスのコード(上:C#、下:VB)
前回のものとほぼ同じだが、NowTimeプロパティの型が異なる。

 これをバインドするテキスト・ブロックを、次のコードのようにしてMainPage.xamlファイルにXAMLで定義する。

<TextBlock x:Name="textClock1" FontSize="120" Foreground="DarkGoldenrod"
    Text="{Binding NowTime}" />

時刻表示のためのテキスト・ブロック(XAML)
NowTimeプロパティ(=DateTimeOffset型)をそのままTextプロパティにバインドする。

 最後に、MainPageクラスのコンストラクタで、テキスト・ブロックのデータ・コンテキストにClockクラスのオブジェクトをセットする(次のコード)。

// 「デジタル時計」クラスのインスタンス
private Clock _clock1 = new Clock();

public MainPage()
{
  this.InitializeComponent();

  // 【1】テキスト・ブロックのデータ・コンテキストに設定
  //      ※ DateTimeOffset をそのままバインド (XAMLで定義)
  textClock1.DataContext = _clock1;
}

' 「デジタル時計」クラスのインスタンス
Private _clock1 As Clock = New Clock()

Public Sub New()
  ' この呼び出しはデザイナーで必要です。
  InitializeComponent()

  ' 【1】テキスト・ブロックのデータ・コンテキストに設定
  '      ※ DateTimeOffset をそのままバインド (XAMLで定義)
  textClock1.DataContext = _clock1

End Sub

「デジタル時計」のインスタンスをテキスト・ブロックのデータ・コンテキストに設定するコード(上:C#、下:VB)

 さて、どうなるだろうか? Textプロパティはstring型で、DateTimeOffset型とは型が合わないからエラーになるだろうか? 実行して確かめてみよう(次の画像)。

DateTimeOffset型をTextプロパティにバインドした画面(Win 8/WP 8)
DateTimeOffset型をTextプロパティにバインドした画面(Win 8/WP 8) DateTimeOffset型をTextプロパティにバインドした画面(Win 8/WP 8)

 実行時エラーにはならないが、「日付け+時刻」という長い文字列が表示されている(末尾は画面の右にはみ出してしまっている)。string型のプロパティにデータ・バインドした場合は、バインドしたオブジェクトのToStringメソッドが自動的に呼び出されることから、このような結果になったのである。

DateTimeOffset型をTextプロパティにバインドする際にフォーマットを指定するには

 バインドするオブジェクトに標準で備わっているToStringメソッドで適切な表示ができるのならそれで問題無いが、上の図のようにToStringメソッドでは表示が長すぎる場合もあるし、指定したフォーマットに変換して表示したい場合もあるだろう。そのためには、指定したフォーマットにデータを変換してくれる「バリュー・コンバータ」を用意して、データ・バインド時に指定するとよい。

 バリュー・コンバータは、Windows.UI.Xaml.Data名前空間(WP 8ではSystem.Windows.Data名前空間)のIValueConverterインターフェイスを継承(VBでは「実装」)して作成する。このインターフェイスには、正方向(データ→画面)の変換を行うConvertメソッドと逆方向(画面→データ)の変換を行うConvertBackメソッドが定義されているので、それらを実装する。

 例えば、DateTimeOffset型のデータを「HH:mm:ss」形式の文字列にフォーマットするバリュー・コンバータのコードは、次のようになる。正方向(データ→画面)の変換しか想定しないのであれば、このコードのようにConvertメソッドだけをきちんと実装し、ConvertBackメソッドは常にDependencyProperty.UnsetValue(Windows.UI.Xaml名前空間/System.Windows名前空間)を返すようにしても構わない。まず、Win 8用のコードを示す。

class DateTimeToHhMmSsConverter : Windows.UI.Xaml.Data.IValueConverter
{
  // 正方向(データ→画面)の変換
  public object Convert(object value, Type targetType,
                        object parameter, string language)
  {
    if (targetType == typeof(string))
      if (value is DateTimeOffset)
        return ((DateTimeOffset)value).ToString("HH:mm:ss");

    return Windows.UI.Xaml.DependencyProperty.UnsetValue;
  }

  // 逆方向(画面→データ)の変換(利用を想定していない)
  public object ConvertBack(object value, Type targetType,
                            object parameter, string language)
  {
    return Windows.UI.Xaml.DependencyProperty.UnsetValue;
  }
}

Public Class DateTimeToHhMmSsConverter
  Implements Windows.UI.Xaml.Data.IValueConverter

  ' 正方向(データ→画面)の変換
  Public Function Convert(value As Object, targetType As Type, parameter As Object, _
                          language As String) _
                   As Object Implements Windows.UI.Xaml.Data.IValueConverter.Convert
    If (targetType Is GetType(String)) Then
      If (TypeOf value Is DateTimeOffset) Then
        Return DirectCast(value, DateTimeOffset).ToString("HH:mm:ss")
      End If
    End If

    Return Windows.UI.Xaml.DependencyProperty.UnsetValue
  End Function

  ' 逆方向(画面→データ)の変換(利用を想定していない)
  Public Function ConvertBack(value As Object, targetType As Type, parameter As Object, _
                              language As String) _
                  As Object Implements Windows.UI.Xaml.Data.IValueConverter.ConvertBack
    Return Windows.UI.Xaml.DependencyProperty.UnsetValue
  End Function
End Class

Win 8用のDateTimeOffset型を文字列に変換するバリュー・コンバータのコード(上:C#、下:VB)
想定外(バインド先がstring型ではない、データがDateTimeOffset型ではない、変換方向が逆)のときは、例外を出すようにしてある。

 一方、WP8用のコードは次のようになる。

public class DateTimeToHhMmSsConverter : System.Windows.Data.IValueConverter
{
  // 正方向(データ→画面)の変換
  public object Convert(object value, Type targetType, object parameter,
                        System.Globalization.CultureInfo culture)
  {
    if (targetType == typeof(string))
      if (value is DateTimeOffset)
        return ((DateTimeOffset)value).ToString("HH:mm:ss");

    return System.Windows.DependencyProperty.UnsetValue;
  }

  // 逆方向(画面→データ)の変換(利用を想定していない)
  public object ConvertBack(object value, Type targetType, object parameter,
                            System.Globalization.CultureInfo culture)
  {
    return System.Windows.DependencyProperty.UnsetValue;
  }
}

Public Class DateTimeToHhMmSsConverter
  Implements System.Windows.Data.IValueConverter

  ' 正方向(データ→画面)の変換
  Public Function Convert(value As Object, targetType As Type, parameter As Object,
                          culture As Globalization.CultureInfo) _
                  As Object Implements System.Windows.Data.IValueConverter.Convert
    If (targetType Is GetType(String)) Then
      If (TypeOf value Is DateTimeOffset) Then
        Return DirectCast(value, DateTimeOffset).ToString("HH:mm:ss")
      End If
    End If
    Return System.Windows.DependencyProperty.UnsetValue
  End Function

  ' 逆方向(画面→データ)の変換(利用を想定していない)
  Public Function ConvertBack(value As Object, targetType As Type, parameter As Object,
                              culture As Globalization.CultureInfo) _
                  As Object Implements System.Windows.Data.IValueConverter.ConvertBack
    Return System.Windows.DependencyProperty.UnsetValue
  End Function
End Class

WP 8用のDateTimeOffset型を文字列に変換するバリュー・コンバータのコード(上:C#、下:VB)
Win 8用とは、以下の点が異なる。
・IValueConverterとDependencyPropertyの名前空間
・クラスはpublicとすること
・両メソッドの第4引数が異なる

 このバリュー・コンバータを画面のXAMLコードで使いたいのだが、それにはまず画面から使える場所にバリュー・コンバータのインスタンスを定義しなければならない。その場所とは、画面そのものかApp.xamlファイルである。ここでは、画面そのもの(MainPage.xamlファイル)に定義してみよう。次のようにページのResources要素内に記述する。

<common:LayoutAwarePage.Resources>

  …… 省略 ……

  <local:DateTimeToHhMmSsConverter x:Key="DateTimeValueConverter" />
</common:LayoutAwarePage.Resources>

Win 8用のMainPage画面に定義したバリュー・コンバータのインスタンス(XAML)
DateTimeToHhMmSsConverterクラスのインスタンスをDateTimeValueConverterという名前で定義している。
[新しいアプリケーション(XAML)]プロジェクト・テンプレートから作成したプロジェクトなどではResources要素がない場合がある。この場合はPage.Resources要素などを適切に追加したうえで、その内部に上記のコードを追加する。

<phone:PhoneApplicationPage

    …… 省略 ……

    xmlns:local="clr-namespace:MetroTips032"
  >

  <phone:PhoneApplicationPage.Resources>
    <local:DateTimeToHhMmSsConverter x:Key="DateTimeValueConverter"/>
  </phone:PhoneApplicationPage.Resources>

WP 8用のMainPage画面に定義したバリュー・コンバータのインスタンス(XAML)
既定ではページにResources要素がないので、Resources要素全体を記述する。また、ページの開始タグに名前空間の定義も追加する。ここでは「MetroTips032」という名前空間名になっているが、適宜変更してほしい。

 ここで、バリュー・コンバータのインスタンスを定義するタグの名前としては、バリュー・コンバータの名前空間/クラス名を使う*1。そして、バリュー・コンバータのインスタンスを画面のXAMLで使うときには、x:Key属性で指定された方の名前を使うのだ。上のXAMLコードでは、それを明確にするためにわざとタグ名とx:Key属性に異なる名前を使ったが、同じ名前にしても構わない。

*1 タグ名の前にある「local:」という接頭辞は名前空間を指定している。ページの先頭で、「local:」は「xmlns:local="using:MetroTips032CS"」や「xmlns:local="clr-namespace:MetroTips032"」のように名前空間のエイリアス(別名)として定義されているからだ。


 テキスト・ブロックのTextプロパティにバインドするときに、このバリュー・コンバータのインスタンスを介するには、次のようにXAMLを定義する。

<TextBlock x:Name="textClock2" FontSize="120" Foreground="DarkCyan"
   Text="{Binding NowTime, Converter={StaticResource DateTimeValueConverter}}"
/>

時刻表示のためのテキスト・ブロック(XAML)
バリュー・コンバータを介してNowTimeプロパティ(=DateTimeOffset型)をTextプロパティにバインドする。

 最後に、MainPageクラスのコンストラクタで、テキスト・ブロックのデータ・コンテキストにClockクラスのオブジェクトをセットすれば完成だ(次のコード)。

public MainPage()
{
  this.InitializeComponent();

  …… 省略 ……

  // 【2】テキスト・ブロックのデータ・コンテキストに設定
  //      ※ バリュー・コンバータを介してDateTimeOffsetをバインド (XAMLで定義)
  textClock2.DataContext = _clock1;
}

Public Sub New()
  ' この呼び出しはデザイナーで必要です。
  InitializeComponent()

  …… 省略 ……

  ' 【2】テキスト・ブロックのデータ・コンテキストに設定
  '      ※ バリュー・コンバータを介してDateTimeOffsetをバインド (XAMLで定義)
  textClock2.DataContext = _clock1

End Sub

「デジタル時計」のインスタンスをテキスト・ブロックのデータ・コンテキストに設定するコード(上:C#、下:VB)

 実行してみると、次の画像のようにフォーマット済みの時刻が表示される。

2段目の表示が、バリュー・コンバータを介してDateTimeOffset型をバインドしたもの(Win 8/WP 8)
2段目の表示が、バリュー・コンバータを介してDateTimeOffset型をバインドしたもの(Win 8/WP 8) 2段目の表示が、バリュー・コンバータを介してDateTimeOffset型をバインドしたもの(Win 8/WP 8)

string型以外のプロパティにバインドするには?

 それでは、バインドするコントロールのプロパティがstring型でないときはどうだろうか? ここではbool型/Boolean型のデータをコントロールのVisibilityプロパティ(=Windows.UI.Xaml名前空間のVisibility列挙型)にバインドしてみよう。

 サンプルとして、「デジタル時計」クラス(=Clockクラス)に秒が偶数か奇数かを表すプロパティを追加し、それをEllipseコントロールのVisibilityプロパティにバインドしてみよう。まず、Clockクラスを次のコードのように改修する(太字が追加部分)。

public class Clock : INotifyPropertyChanged
{
  // 現在時刻を表すプロパティ
  public DateTimeOffset NowTime { get; private set; }

  // 秒が偶数のとき true
  public bool IsEven { get; private set; }

  // 秒が奇数のとき true
  public bool IsOdd { get; private set; }

  …… 省略 ……

  private async void Run()
  {
    …… 省略 ……

        // 秒が変わったら、プロパティに時刻をセットし、イベントを発火させる
        this.NowTime = nowTime;
        if (this.PropertyChanged != null)
          this.PropertyChanged(this, new PropertyChangedEventArgs("NowTime"));

        bool isEvenSec = (nowTime.Second % 2 == 0);
        this.IsEven = isEvenSec;
        if (this.PropertyChanged != null)
          this.PropertyChanged(this, new PropertyChangedEventArgs("IsEven"));
        this.IsOdd = !isEvenSec;
        if (this.PropertyChanged != null)
          this.PropertyChanged(this, new PropertyChangedEventArgs("IsOdd"));

        lastTime = nowTime;

    …… 省略 ……

Public Class Clock
  Implements INotifyPropertyChanged

  ' 現在時刻を表すプロパティ
  Private _nowTime As DateTimeOffset

  …… 省略 ……

  ' 秒が偶数のとき True
  Private _isEven As Boolean
  Public Property IsEven As Boolean
    Get
      Return _isEven
    End Get
    Private Set(value As Boolean)
      _isEven = value
    End Set
  End Property

  ' 秒が奇数のとき True
  Private _isOdd As Boolean
  Public Property IsOdd As Boolean
    Get
      Return _isOdd
    End Get
    Private Set(value As Boolean)
      _isOdd = value
    End Set
  End Property

  …… 省略 ……

  Private Async Sub Run()

    …… 省略 ……

        ' 秒が変わったら、プロパティに時刻をセットし、イベントを発火させる
        Me.NowTime = nowTime
        RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs("NowTime"))

        Dim isEvenSec As Boolean = (nowTime.Second Mod 2 = 0)
        Me.IsEven = isEvenSec
        RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs("IsEven"))
        Me.IsOdd = Not isEvenSec
        RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs("IsOdd"))

        lastTime = nowTime

    …… 省略 ……

「デジタル時計」クラスのコード(上:C#、下:VB)
IsEvenプロパティ(秒が偶数のときにtrue)とIsOddプロパティ(秒が奇数のときtrue)を追加した。

 この追加したプロパティを2つのEllipseコントロールのVisibilityプロパティにバインドする(次の画像とXAMLコード)。

VS 2012のXAMLデザイナで、画面にEllipseコントロールを2つ配置したところ(Win 8) VS 2012のXAMLデザイナで、画面にEllipseコントロールを2つ配置したところ(Win 8)

<StackPanel Margin="0,20,0,0">
  <TextBlock Text="bool を Visibility プロパティにバインド"
             FontSize="21" />
  <Ellipse x:Name="RedCircle" Width="90" Height="90"
           Fill="DarkRed" HorizontalAlignment="Left"
           Visibility="{Binding IsEven}" />
  <Ellipse x:Name="GreenCircle" Width="90" Height="90"
           Fill="Green" HorizontalAlignment="Left"
           Visibility="{Binding IsOdd}" />
</StackPanel>

2つのEllipseコントロール(XAML)
一方のVisibilityプロパティはClockクラスのIsEvenプロパティに、他方はIsOddプロパティにバインドした。

 これが正しくバインドされれば、1秒ごとに表示されるEllipseコントロールが切り替わり、赤と緑の円が点滅するような表示になるはずである。コードビハインドで、ClockクラスのインスタンスをEllipseコントロールのデータ・コンテキストに結び付けてみよう(次のコード)。

public MainPage()
{
  this.InitializeComponent();

  …… 省略 ……

  // 【3】図形のデータ・コンテキストに設定
  RedCircle.DataContext = _clock1;
  GreenCircle.DataContext = _clock1;
}

Public Sub New()
  ' この呼び出しはデザイナーで必要です。
  InitializeComponent()

  …… 省略 ……

  ' 【3】図形のデータ・コンテキストに設定
  RedCircle.DataContext = _clock1
  GreenCircle.DataContext = _clock1
End Sub

「デジタル時計」のインスタンスを2つのEllipseコントロールのデータ・コンテキストに設定するコード(上:C#、下:VB)

 しかし、実行してみると、Ellipseコントロールが2つとも表示されたままになる。つまり、コントロールのVisibilityプロパティが変化しないのだ。これは、bool型/Boolean型をVisibility列挙型に変換する方法をデータ・バインディングが知らないからである。

 これを解決するには、bool型/Boolean型をVisibility列挙型に変換するバリュー・コンバータを提供してやればよい。まさにこの処理を行ってくれるバリュー・コンバータが、Win 8用のプロジェクトでは「グリッド アプリケーション(XAML)」などのプロジェクト・テンプレートのCommonフォルダに「BooleanToVisibilityConverter」クラスとして入っている*2。そして、それをWP 8用に移植したのが次のコードだ。C#の場合は、WP 8用のプロジェクトにCommonフォルダを作成して、そこにBooleanToVisibilityConverterクラスを作成するか、プロジェクトの直下にクラスを作成し、明示的に名前空間Commonを宣言しておく。VBの場合はプロジェクトの直下にクラスを作成し、「Namespace Common」として名前空間を明示的に宣言しておく。

public sealed class BooleanToVisibilityConverter
                    : System.Windows.Data.IValueConverter
{
  public object Convert(object value, Type targetType, object parameter,
                        CultureInfo culture)
  {
    return (value is bool && (bool)value)
            ? Visibility.Visible
            : Visibility.Collapsed;
  }

  public object ConvertBack(object value, Type targetType, object parameter,
                            CultureInfo culture)
  {
    return value is Visibility && (Visibility)value == Visibility.Visible;
  }
}

Namespace Common
  Public NotInheritable Class BooleanToVisibilityConverter
    Implements System.Windows.Data.IValueConverter

    Public Function Convert(value As Object, targetType As Type, parameter As Object,
                            culture As Globalization.CultureInfo) _
                    As Object Implements System.Windows.Data.IValueConverter.Convert
      If TypeOf value Is Boolean AndAlso DirectCast(value, Boolean) Then Return Visibility.Visible
      Return Visibility.Collapsed
    End Function

    Public Function ConvertBack(value As Object, targetType As Type, parameter As Object,
                                culture As Globalization.CultureInfo) _
                    As Object Implements System.Windows.Data.IValueConverter.ConvertBack
      Return TypeOf value Is Visibility AndAlso DirectCast(value, Visibility) = Visibility.Visible
    End Function
  End Class
End Namespace

WP 8用のbool型/Boolean型をVisibility列挙型に変換するバリュー・コンバータのコード(上:C#、下:VB)
Win 8用のプロジェクト・テンプレートに含まれていたものを、WP 8用に移植した。

*2 プロジェクトのCommonフォルダにBooleanToVisibilityConverterクラスが存在しない場合は、そのプロジェクトに(新しいプロジェクト項目として)[基本ページ]を追加してほしい。するとメッセージボックスが出てきて、「(前略)不足しているファイルを自動的に追加しますか?」と尋ねられるので[はい]と答えると、Commonフォルダにいくつかのファイルが自動生成される。自動生成されたファイルの中に、BooleanToVisibilityConverter.cs/.vbファイルがあるはずだ。なお、作ったページ自体は不要なので削除しておく。
 また、この操作によってVS 2012の動作が不安定になる場合があるので、できるだけプロジェクトの作成直後に行ってほしい。


 BooleanToVisibilityConverterバリュー・コンバータを使うために、まずそのインスタンスを画面のResources要素に定義する(次のコード)。

<common:LayoutAwarePage.Resources>

  …… 省略 ……

  <common:BooleanToVisibilityConverter x:Key="BoolToVisibilityConverter"/>
</common:LayoutAwarePage.Resources>

Win 8用のMainPage画面に定義したバリュー・コンバータのインスタンス(XAML)
BooleanToVisibilityConverterクラスのインスタンスをBoolToVisibilityConverterという名前で定義している。
[新しいアプリケーション]プロジェクト・テンプレートから作成したプロジェクトなどでは名前空間commonが定義されていない場合がある。この場合はPage定義中に「xmlns:common="using:MetroTips032CS.Common"」などと名前空間の定義を追加で記述する。

<phone:PhoneApplicationPage

    …… 省略 ……

    xmlns:common="clr-namespace:MetroTips032.Common"
  >

  <phone:PhoneApplicationPage.Resources>

    …… 省略 ……

    <common:BooleanToVisibilityConverter x:Key="BoolToVisibilityConverter"/>
  </phone:PhoneApplicationPage.Resources>

WP 8用のMainPage画面に定義したバリュー・コンバータのインスタンス(XAML)
ページの開始タグに名前空間の定義も追加する。ここでは「MetroTips032.Common」という名前空間名になっているが、適宜変更してほしい。

 最後に、Ellipseコントロールにバインドしている部分でバリュー・コンバータを指定する。

<StackPanel Margin="0,20,0,0">
  <TextBlock
   Text="bool をバリュー・コンバータを介して Visibility プロパティにバインド"
   FontSize="21" />
  <Ellipse x:Name="RedCircle" Width="90" Height="90"
   Fill="DarkRed" HorizontalAlignment="Left"
   Visibility="{Binding IsEven, Converter={StaticResource BoolToVisibilityConverter}}" />
  <Ellipse x:Name="GreenCircle" Width="90" Height="90"
   Fill="Green" HorizontalAlignment="Left"
   Visibility="{Binding IsOdd, Converter={StaticResource BoolToVisibilityConverter}}" />
</StackPanel>

2つのEllipseコントロール(XAML)
両方のVisibilityプロパティのバインディング指定に、バリュー・コンバータの指定を追加した。

 実行してみると、今度はうまくいく。秒が偶数のときと奇数のときで表示されるEllipseコントロールが切り替わり、まるでコントロールの色が変化しているように見える(次の画像)。

2つのEllipseコントロールの表示/非表示がデータ・バインドで切り替わる様子(Win 8/WP 8)
2つのEllipseコントロールの表示/非表示がデータ・バインドで切り替わる様子(Win 8/WP 8) 2つのEllipseコントロールの表示/非表示がデータ・バインドで切り替わる様子(Win 8/WP 8)

まとめ

 データ・バインドで、バインド時に以下に示すような状況で何らかの変換を行いたいときにはバリュー・コンバータを利用する。

  • 表示時に文字列のフォーマットを整えたい場合
  • データの型とコントロールのプロパティの型が合わない場合

 なお、本稿ではXAMLコードでバリュー・コンバータを設定したが、コードビハインドでBindingオブジェクトにセットすることも可能である(BindingオブジェクトのConverterプロパティ)。

 バリュー・コンバータについて詳しくは、次のドキュメントを参照してほしい。

「WinRT/Metro TIPS」のインデックス

WinRT/Metro TIPS

Copyright© Digital Advantage Corp. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。