連載
» 2014年02月27日 13時20分 公開

WinRT/Metro TIPS:nullをバインドして「なし」と表示するには?[Windows 8.1ストアアプリ開発]

データバインディングを使って、データがnullのときに、例えば「(なし)」のように表示する方法として、従来のバリューコンバーターを使う方法と、Win 8.1からのプロパティ設定による方法を解説する。

[山本康彦(http://www.bluewatersoft.jp/),BluewaterSoft]
WinRT/Metro TIPS
業務アプリInsider/Insider.NET

powered by Insider.NET

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

連載目次

 データバインディングを使っていて、データがnull(VBではNothing)のときはnullだと分かるように表示を変えたいときはないだろうか? 例えば、データが空文字のときは何も表示せず、データがnullのときは「(なし)」と表示したいような場合だ。Windows 8(以降、Win 8)のWindowsストアアプリでは、それだけのためにバリューコンバーターを書く必要があった。それがWindows 8.1(以降、Win 8.1)では、バインディングのプロパティを設定するだけで可能になったのだ。本稿では、バリューコンバーターを使う方法と新しいプロパティによる方法の両方を解説する。なお、本稿のサンプルは「Windows Store app samples:MetroTips #64(Windows 8.1版)」からダウンロードできる。

事前準備

 Win 8.1用のWindowsストアアプリ(以降、Win 8.1アプリ)を開発するには、Win 8.1とVisual Studio 2013(以降、VS 2013)が必要である。本稿ではOracle VM VirtualBox上で64bit版Windows 8.1 Pro(日本語版)とVisual Studio Express 2013 for Windows(日本語版)*1を使用している。

*1 マイクロソフト公式ダウンロードセンターの「Microsoft Visual Studio Express 2013 for Windows」から無償で入手できる。


ベースとなるプログラムを用意する

 これから行う実験のベースとなるプログラムを作っておく。本稿ではXAMLコードの詳しい説明は省略させていただくので、次の画像を参考にして適宜UIを構築してほしい。

サンプルコードを実行している画面 サンプルコードを実行している画面
右側に入力した文字列が、データバインディングで左側に表示される。

 ベースとなるプログラムでは、任意の文字列を与えてデータバインディングが機能していることを確かめるコードと、データをnullにするコードを実装する。

 まず、Windowsストアアプリのプロジェクトを作るときに、[新しいアプリケーション (XAML)]を選ぶ。出来上がったプロジェクトから「MainPage.xaml」ファイルを削除し、あらためて[基本ページ]を「MainPage.xaml」ファイルとして追加する。これにより、プロジェクトにCommonフォルダーとその中にソースコードが幾つか自動生成される。これは、以降でデータバインディングの実装を簡単に行うために必要だ。

 次に、「MainPage.xaml」ファイルで、任意の文字列を入力するためのTextBoxコントロール(Windows.UI.Xaml.Controls名前空間)を配置して「inputText」と名前を付ける。その文字列をページのDefaultViewModelオブジェクトにセットするためのButtonコントロール(Windows.UI.Xaml.Controls名前空間)を置き、そのClickイベントハンドラーに次のコードを記述する。

private void SetButton_Click(object sender, RoutedEventArgs e)
{
  this.DefaultViewModel["SampleData"] = this.inputText.Text;
}

Private Sub SetButton_Click(sender As Object, e As RoutedEventArgs)
  Me.DefaultViewModel("SampleData") = Me.inputText.Text
End Sub

TextBoxコントロールの文字列をDefaultViewModelオブジェクトにセットするコード(上:C#、下:VB)
「SampleData」というキーで文字列をセットした。
なお、「inputText」TextBoxコントロールを双方向バインドにして直接反映させることも可能だが、そのようにしてしまうとデータをnullにしたときの挙動が分かりづらくなるため、あえてこのようにしている(双方向バインドにしてデータをnullに変えたとき、TextBoxコントロールはそれを空文字に変えてバインドデータに書き戻すようだ)。

 次に、データを表示するためのTextBoxコントロールを配置して、上のコードでセットした文字列をバインドする(次のコード)。

<TextBox ……省略……
         Text="{Binding Path=SampleData}" />

データを表示するためのTextBoxコントロール(XAML)
自動生成されたコードによって、DefaultViewModelオブジェクトがページのDataContextにセットされている。そのため、「SampleData」というキーでデータバインドのパスを指定すれば、先ほどコードビハインドでセットした文字列がバインドされる。

 これで実行してみて、データバインディングが機能していることを確かめてほしい。「inputText」TextBoxコントロールに文字を入力してからボタンをタップすると、データを表示するためのTextBoxコントロールの方にその文字列が反映されるはずだ。

 次に、もう1つButtonコントロールを配置し、そのClickイベントハンドラーでバインドデータをnullにする(次のコード)。

private void NullButton_Click(object sender, RoutedEventArgs e)
{
  this.DefaultViewModel["SampleData"] = null;
}

Private Sub NullButton_Click(sender As Object, e As RoutedEventArgs)
  Me.DefaultViewModel("SampleData") = Nothing
End Sub

バインドデータをnullにするコード(上:C#、下:VB)

 これを実行してみると、バインドデータが空文字でもnullでもバインド先のTextBoxコントロールの表示は同じになる(=何も表示されない)ことが確認できる。

バリューコンバーターを使う方法

 データがnull(Nothing)であることが分かるように表示を変えるには、Win 8では次のようなバリューコンバーターを書いて使っていた(Win 8.1でも動作する)。

 プロジェクトに新しくクラスを追加し、「ObjectToDisplayStringConverter」という名前にする。そして次のようなコードを記述する。

using System;

namespace MetroTips064CS
{
  public sealed class ObjectToDisplayStringConverter : Windows.UI.Xaml.Data.IValueConverter
  {
    public object Convert(object value, Type targetType, object parameter, string language)
    {
      if (value == null)
        return "(なし)";

      return value.ToString();
    }

    public object ConvertBack(object value, Type targetType, object parameter, string language)
    {
      return Windows.UI.Xaml.DependencyProperty.UnsetValue;
    }
  }
}

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

  Public Function Convert(value As Object, targetType As Type, parameter As Object, language As String) _
                  As Object Implements IValueConverter.Convert
    If (value Is Nothing) Then
      Return "(なし)"
    End If
    Return value.ToString()
  End Function

  Public Function ConvertBack(value As Object, targetType As Type, parameter As Object, language As String) _
                  As Object Implements IValueConverter.ConvertBack
    Return Windows.UI.Xaml.DependencyProperty.UnsetValue
  End Function
End Class

バリューコンバーターのコード(上:C#、下:VB)
このコンバーターは、バインドデータがnullのときは「(なし)」という文字列に変換する。nullでなければ、ToString()メソッドを呼び出して文字列に変換する。

 このバリューコンバーターを、バインドデータを表示するときに使うのだ。その詳しい手順は「WinRT/Metro TIPS:文字列以外の値をコントロールにバインドするには?[Win 8/WP 8]」をご覧いただきたい。次のようなコードになる。

……省略……
<Page.Resources>
  <local:ObjectToDisplayStringConverter x:Key="ObjectToDisplayStringConverter" />
  ……省略……
</Page.Resources>
……省略……

  <TextBox ……省略……
           Text="{Binding Path=SampleData, Converter={StaticResource ObjectToDisplayStringConverter}}" />

……省略……

データを表示するときにバリューコンバーターを使う(XAML)
ページのXAMLコードに太字の部分を追加する。<Page.Resources>要素にObjectToDisplayStringConverterの定義を追加することと、データバインディングの指定にConverterプロパティを追加することだ。

 これで実行して、バインドデータをnullにしてみよう。バリューコンバーターによって変換された文字列「(なし)」がバインド先に表示されるはずだ。

TargetNullValueプロパティを使う方法

 Win 8.1では、上のバリューコンバーターを使ったのと同等のことが、TargetNullValueプロパティを使うだけで実現できてしまう(次のコード)。

<TextBox ……省略……
         Text="{Binding Path=SampleData, TargetNullValue='(なし)'}" />

データを表示するときにTargetNullValueプロパティを指定する(XAML)

 たったこれだけで、データがnullのときには「(なし)」と表示されるのだ(次の画像)。

データがnullのときに「(なし)」と表示される データがnullのときに「(なし)」と表示される
左側の上はバリューコンバーターを、下はTargetNullValueプロパティを使用している。

バインドされていないときに使うFallbackValueプロパティ

 さらにWin 8.1では、バインド時に指定できるプロパティとして、FallbackValueプロパティも追加されている。前述のTargetNullValueプロパティは、バインドされているデータがnullのときに働くものだった。対して、FallbackValueプロパティは、バインドデータがないときに働くものである。

 もう1つButtonコントロールを配置し、そのClickイベントハンドラーでバインドデータを削除する(次のコード)。

private void RemoveButton_Click(object sender, RoutedEventArgs e)
{
  this.DefaultViewModel.Remove("SampleData");
}

Private Sub RemoveButton_Click(sender As Object, e As RoutedEventArgs)
  Me.DefaultViewModel.Remove("SampleData")
End Sub

バインドデータを削除するコード(上:C#、下:VB)

 このようにバインドデータそのものを削除してしまうと、データバインディングは実行されない。バリューコンバーターもTargetNullValueプロパティも働かないため、何も表示されない。

 このようなときに何か表示したいとなると、Win 8ではコードビハインドに処理を書くしかなかった。Win 8.1では、新設されたFallbackValueプロパティを指定するだけだ(次のコード)。

<TextBox ……省略……
         Text="{Binding Path=SampleData, TargetNullValue='(なし)', FallbackValue='(バインド無し)'}" />

データがバインドされていないときに表示する文字列をFallbackValueプロパティで指定する(XAML)

 これで次の画像のように、バインドデータそのものがないときには「(バインド無し)」と表示される。

データがバインドされていないときに「(バインド無し)」と表示される データがバインドされていないときに「(バインド無し)」と表示される
左側の下でFallbackValueプロパティを使用している。

まとめ

 バインドしているデータがnullのときに特定の文字列を表示するには、Win 8.1ではTargetNullValueプロパティを使えばよい。

 また、開発中にバインド先に何も表示されなかったとき、その原因はデータが空文字なのかnullなのか、あるいはデータバインディングに失敗しているのか、判断に迷うことがあるだろう。Win 8.1でTargetNullValueプロパティとFallbackValueプロパティを指定しておけば、原因が明瞭になる。

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

WinRT/Metro TIPS

Copyright© 1999-2017 Digital Advantage Corp. All Rights Reserved.

@IT Special

- PR -

TechTargetジャパン

この記事に関連するホワイトペーパー

RSSについて

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

メールマガジン登録

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