nullをバインドして「なし」と表示するには?[Windows 8.1ストアアプリ開発]:WinRT/Metro TIPS
データバインディングを使って、データがnullのときに、例えば「(なし)」のように表示する方法として、従来のバリューコンバーターを使う方法と、Win 8.1からのプロパティ設定による方法を解説する。
powered by Insider.NET
データバインディングを使っていて、データが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
「SampleData」というキーで文字列をセットした。
なお、「inputText」TextBoxコントロールを双方向バインドにして直接反映させることも可能だが、そのようにしてしまうとデータをnullにしたときの挙動が分かりづらくなるため、あえてこのようにしている(双方向バインドにしてデータをnullに変えたとき、TextBoxコントロールはそれを空文字に変えてバインドデータに書き戻すようだ)。
次に、データを表示するためのTextBoxコントロールを配置して、上のコードでセットした文字列をバインドする(次のコード)。
<TextBox ……省略……
Text="{Binding Path=SampleData}" />
自動生成されたコードによって、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でもバインド先の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
このコンバーターは、バインドデータが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コードに太字の部分を追加する。<Page.Resources>要素にObjectToDisplayStringConverterの定義を追加することと、データバインディングの指定にConverterプロパティを追加することだ。
これで実行して、バインドデータをnullにしてみよう。バリューコンバーターによって変換された文字列「(なし)」がバインド先に表示されるはずだ。
TargetNullValueプロパティを使う方法
Win 8.1では、上のバリューコンバーターを使ったのと同等のことが、TargetNullValueプロパティを使うだけで実現できてしまう(次のコード)。
<TextBox ……省略……
Text="{Binding Path=SampleData, TargetNullValue='(なし)'}" />
たったこれだけで、データがnullのときには「(なし)」と表示されるのだ(次の画像)。
バインドされていないときに使う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
このようにバインドデータそのものを削除してしまうと、データバインディングは実行されない。バリューコンバーターもTargetNullValueプロパティも働かないため、何も表示されない。
このようなときに何か表示したいとなると、Win 8ではコードビハインドに処理を書くしかなかった。Win 8.1では、新設されたFallbackValueプロパティを指定するだけだ(次のコード)。
<TextBox ……省略……
Text="{Binding Path=SampleData, TargetNullValue='(なし)', FallbackValue='(バインド無し)'}" />
これで次の画像のように、バインドデータそのものがないときには「(バインド無し)」と表示される。
まとめ
バインドしているデータがnullのときに特定の文字列を表示するには、Win 8.1ではTargetNullValueプロパティを使えばよい。
また、開発中にバインド先に何も表示されなかったとき、その原因はデータが空文字なのかnullなのか、あるいはデータバインディングに失敗しているのか、判断に迷うことがあるだろう。Win 8.1でTargetNullValueプロパティとFallbackValueプロパティを指定しておけば、原因が明瞭になる。
Copyright© Digital Advantage Corp. All Rights Reserved.