WP TIPS に戻る

ListBox に項目がないときのメッセージを簡単に表示する

サンプルプロジェクト ListBox_empty_message.zip

listBox_empty_message-01.jpg

WP7 ではソフトを開発しただけでは終わりません。最終的には AppHub にアプリを申請し通らなければ、野良アプリとして一生を終えてしまいかねません。
その AppHub 規約の中で 「表示するコンテンツが無い場合は、その旨を表示する」 というものがあるようです (Twitter で見かけた)。
たとえば ListBox 等で表示する項目が無い場合は、右の画像のようにメッセージを表示する必要があります。標準の Picture Hub などでも「同期していません。コンピュータに接続してビデオを同期させてください。」などのメッセージが表示されています。

いったいこれはどうすればいいのでしょうか?

空の場合のメッセージの表示

空のメッセージを表示する方法として、まず ListBox に表示する項目が無い場合、ListBox にダミーの項目を表示しておくという手法が考えられます。
しかし本来のテンプレートとダミー項目のテンプレート双方を用意する必要がありますし、切り替えも面倒です。

ここで紹介する方法ではコンバータを使用して、空のメッセージを表示してみます。

考え方としては、

  1. ListBox の下に同じ大きさの StackPanel を配置、その中の TextBlock に空のメッセージを表示しておく。
  2. あとは ListBox.ItemSource.Count < 1 であれば ListBox.Visibility = Collapse, StackPanel.Visibility = Visible にして表示を切り替える。

とすれば項目数に合わせて ListBox, StackPanel の表示が相互に切り替わります。

SourceItemVisibilityConverter の実装

以下は、SourceItemVisibilityConverter のソースコードです。
このコンバータは ICollection を引数(value)にとり、その格納数が 1 以上であれば、Visible を返し、それ以外なら Collapsed を返します。
つまり 表示するアイテムがあれば Visible, なければ Collapsed を返すコンバータです。

これをプロジェクトに追加してビルドしておきます。

/// <summary>
/// 指定された ICollection が無ければ Collapse, あれば Visible を返す
/// </summary>
public class SourceItemVisibilityConverter : IValueConverter
{
   // ListBox.Visibility にバインドされているコンバータ
   public virtual object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
   {
       // ICollection を取得→無ければ Collapsed
       ICollection collection = value as ICollection;
       if (collection == null)
           return Visibility.Collapsed;

       // アイテムがあれば Visible, なければ Collapsed
       return collection.Count < 1 ? Visibility.Collapsed : Visibility.Visible;
   }

   public virtual object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
   {
       throw new NotImplementedException();
   }
}

/// <summary>
/// SourceItemVisibilityConverter の逆
/// </summary>
public class SourceItemVisibilityInverseConverter : SourceItemVisibilityConverter
{

   // ListBox.Visibility にバインドされているコンバータ
   public override object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
   {
       Visibility vis = (Visibility) base.Convert(value, targetType, parameter, culture);
       return vis == Visibility.Visible ? Visibility.Collapsed : Visibility.Visible;
   }

   public override object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
   {
       throw new NotImplementedException();
   }

}

Blend でコンバータを配置する

  1. 次に Blend で以下のように、StackPanel, ListBox を配置します。
    ListBox.ItemSource は、PhoneApplicationPage のメンバ Items が追加してあるので、それにバインドしています。
    ※ Blend になれていない方もいらっしゃると思いますので、バインド・コンバータの指定方法手順を書いておきます。
    listBox_empty_message-02.jpg

  2. ListBox の Visibility 右端の■をクリックしてデータバインドを選択します。
    listBox_empty_message-03.jpg

  3. 「要素プロパティ」の「シーン要素」から PhoneApplicationPage を選択し、プロパティ Items を選択します。プロパティ一覧に表示されてない場合は、ドロップダウンメニューから「すべてのプロパティ」を選択してください。
    listBox_empty_message-04.jpg

  4. ダイアログボックスの下矢印をクリックして、ボックスを広げます。「値コンバータ」の欄の「...」ボタンを押します。
    listBox_empty_message-05.jpg

  5. 追加できるコンバータの一覧が表示されますので「SourceItemVisibilityConverter」を選択します。
    ※ここに出てこない場合は SourceItemVisibilityConverter.cs が追加されてないか、ビルドされていない場合です。
    listBox_empty_message-06.jpg

  6. これで完了です。OK ボタンを押してください。
    listBox_empty_message-07.jpg

ここまでの操作で、ListBox.ItemSource のバインド元 Items の値に合わせて、ListBox が表示・非表示されるようになりました。
しかしこのままだと ListBox の下にある StackPanel が透けてしまい、右の画像のようになってしまいます。
この対処方法は、

  1. ListBox.Background を Transparent 以外にする
  2. StackPanel.Visibility に ListBox と同じくコンバータを設定する。

の2つの方法があります。

listBox_empty_message-08.jpg

ListBox.Background を Transparent 以外にするのは、安直な方法ですがここでは StackPanel.Visibility にもコンバータを設定して表示・非表示を切り替えた方が良さそうです。

StackPanel.Visibility にコンバータを設定するには、ListBox と同じように Items のバインドからコンバータを指定します。ただしコンバータの選択では、SourceItemVisibilityConverter ではなく SourceItemVisibilityInverseConverter を選択して、ListBox とは逆の Visibility が設定されるようにしてください。

参考

Application Certification Requirements for Windows Phone