次の方法で共有


Xamarin.Forms CollectionView EmptyView

CollectionView では、表示するデータがない場合に、ユーザーへのフィードバックを提供するために使用できる次のプロパティを定義します。

  • EmptyView (object 型): ItemsSource プロパティが null の場合、または ItemsSource プロパティで指定されたコレクションが null または空の場合に表示される文字列、バインディング、またはビューです。 既定値は null です。
  • EmptyViewTemplate (DataTemplate 型): 指定された EmptyView の書式設定に使用するテンプレートです。 既定値は null です。

これらのプロパティは BindableProperty オブジェクトによってサポートされています。つまり、プロパティはデータ バインディングのターゲットになることができます。

EmptyView プロパティを設定する主な使用シナリオは、CollectionView でのフィルタリング操作でデータが得られなかった場合や、Web サービスからデータを取得しているときにユーザーにフィードバックを表示することです。

Note

EmptyView プロパティは、必要に応じてインタラクティブ コンテンツを含むビューに設定できます。

データ テンプレートの詳細については、「Xamarin.Forms のデータ テンプレート」を参照してください。

データが使用できない場合に文字列を表示する

EmptyView プロパティは文字列に設定できます。この文字列は、ItemsSource プロパティが null の場合、または ItemsSource プロパティで指定されたコレクションが null または空の場合に表示されます。 次の XAML は、このシナリオの例を示しています。

<CollectionView ItemsSource="{Binding EmptyMonkeys}"
                EmptyView="No items to display" />

同等の C# コードを次に示します。

CollectionView collectionView = new CollectionView
{
    EmptyView = "No items to display"
};
collectionView.SetBinding(ItemsView.ItemsSourceProperty, "EmptyMonkeys");

その結果、データ バインドされたコレクションが null であるため、EmptyView プロパティ値として設定された文字列が表示されます。

iOS および Android 上の、テキストが空のビューを含む CollectionView 縦方向リストのスクリーンショット

データが使用できない場合にビューを表示する

EmptyView プロパティはビューに設定できます。このビューは、ItemsSource プロパティが null の場合、または ItemsSource プロパティで指定されたコレクションが null または空の場合に表示されます。 単一のビューでも、複数の子ビューを含むビューでも表示できます。 次の XAML の例は、複数の子ビューを含むビューに設定された EmptyView プロパティを示しています。

<StackLayout Margin="20">
    <SearchBar x:Name="searchBar"
               SearchCommand="{Binding FilterCommand}"
               SearchCommandParameter="{Binding Source={x:Reference searchBar}, Path=Text}"
               Placeholder="Filter" />
    <CollectionView ItemsSource="{Binding Monkeys}">
        <CollectionView.ItemTemplate>
            <DataTemplate>
                ...
            </DataTemplate>
        </CollectionView.ItemTemplate>
        <CollectionView.EmptyView>
            <ContentView>
                <StackLayout HorizontalOptions="CenterAndExpand"
                             VerticalOptions="CenterAndExpand">
                    <Label Text="No results matched your filter."
                           Margin="10,25,10,10"
                           FontAttributes="Bold"
                           FontSize="18"
                           HorizontalOptions="Fill"
                           HorizontalTextAlignment="Center" />
                    <Label Text="Try a broader filter?"
                           FontAttributes="Italic"
                           FontSize="12"
                           HorizontalOptions="Fill"
                           HorizontalTextAlignment="Center" />
                </StackLayout>
            </ContentView>
        </CollectionView.EmptyView>
    </CollectionView>
</StackLayout>

この例では、冗長な ContentView のように見えるものが、EmptyView のルート要素として追加されています。 これは、内部では Xamarin.Forms レイアウトのコンテキストを提供しないネイティブ コンテナーに EmptyView が追加されるためです。 したがって、EmptyView を構成するビューを配置するには、ルート レイアウトを追加する必要があります。その子はルート レイアウト内に配置できるレイアウトです。

同等の C# コードを次に示します。

SearchBar searchBar = new SearchBar { ... };
CollectionView collectionView = new CollectionView
{
    EmptyView = new ContentView
    {
        Content = new StackLayout
        {
            Children =
            {
                new Label { Text = "No results matched your filter.", ... },
                new Label { Text = "Try a broader filter?", ... }
            }
        }
    }
};
collectionView.SetBinding(ItemsView.ItemsSourceProperty, "Monkeys");

SearchBarFilterCommand を実行すると、CollectionView によって表示されるコレクションが、SearchBar.Text プロパティに格納されている検索語でフィルター処理されます。 フィルタリング操作でデータが得られない場合は、EmptyView プロパティ値として設定された StackLayout が表示されます。

iOS および Android 上の、カスタムの空のビューを含む CollectionView の縦方向リストのスクリーンショット

データが使用できない場合にテンプレート化されたカスタム型を表示する

EmptyView プロパティはカスタム型に設定できます。そのテンプレートは、ItemsSource プロパティが null の場合、または ItemsSource プロパティで指定されたコレクションが null または空の場合に表示されます。 EmptyViewTemplate プロパティは、EmptyView の外観を定義する DataTemplate に設定できます。 次の XAML は、このシナリオの例を示しています。

<StackLayout Margin="20">
    <SearchBar x:Name="searchBar"
               SearchCommand="{Binding FilterCommand}"
               SearchCommandParameter="{Binding Source={x:Reference searchBar}, Path=Text}"
               Placeholder="Filter" />
    <CollectionView ItemsSource="{Binding Monkeys}">
        <CollectionView.ItemTemplate>
            <DataTemplate>
                ...
            </DataTemplate>
        </CollectionView.ItemTemplate>
        <CollectionView.EmptyView>
            <views:FilterData Filter="{Binding Source={x:Reference searchBar}, Path=Text}" />
        </CollectionView.EmptyView>
        <CollectionView.EmptyViewTemplate>
            <DataTemplate>
                <Label Text="{Binding Filter, StringFormat='Your filter term of {0} did not match any records.'}"
                       Margin="10,25,10,10"
                       FontAttributes="Bold"
                       FontSize="18"
                       HorizontalOptions="Fill"
                       HorizontalTextAlignment="Center" />
            </DataTemplate>
        </CollectionView.EmptyViewTemplate>
    </CollectionView>
</StackLayout>

同等の C# コードを次に示します。

SearchBar searchBar = new SearchBar { ... };
CollectionView collectionView = new CollectionView
{
    EmptyView = new FilterData { Filter = searchBar.Text },
    EmptyViewTemplate = new DataTemplate(() =>
    {
        return new Label { ... };
    })
};

FilterData 型は、Filter プロパティと、対応する BindableProperty を定義します。

public class FilterData : BindableObject
{
    public static readonly BindableProperty FilterProperty = BindableProperty.Create(nameof(Filter), typeof(string), typeof(FilterData), null);

    public string Filter
    {
        get { return (string)GetValue(FilterProperty); }
        set { SetValue(FilterProperty, value); }
    }
}

EmptyView プロパティは FilterData オブジェクトに設定され、Filter プロパティ データは SearchBar.Text プロパティにバインドされます。 SearchBarFilterCommand を実行すると、CollectionView で表示されるコレクションが、Filter プロパティに格納されている検索語でフィルター処理されます。 フィルタリング操作でデータが得られない場合は、DataTemplate で定義され、EmptyViewTemplate プロパティ値として設定されている Label が表示されます。

iOS および Android 上の、空のビューのテンプレートを含む CollectionView の縦方向リストのスクリーンショット

Note

データを使用できないときにテンプレート化されたカスタム型を表示する場合、EmptyViewTemplate プロパティを複数の子ビューを含むビューに設定できます。

実行時に EmptyView を選択する

データを使用できない場合に EmptyView として表示されるビューは、ResourceDictionary 内の ContentView オブジェクトとして定義できます。 EmptyView プロパティは、実行時にビジネス ロジックに基づいて特定の ContentView に設定できます。 次の XAML は、このシナリオの例を示しています。

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="CollectionViewDemos.Views.EmptyViewSwapPage"
             Title="EmptyView (swap)">
    <ContentPage.Resources>
        <ContentView x:Key="BasicEmptyView">
            <StackLayout>
                <Label Text="No items to display."
                       Margin="10,25,10,10"
                       FontAttributes="Bold"
                       FontSize="18"
                       HorizontalOptions="Fill"
                       HorizontalTextAlignment="Center" />
            </StackLayout>
        </ContentView>
        <ContentView x:Key="AdvancedEmptyView">
            <StackLayout>
                <Label Text="No results matched your filter."
                       Margin="10,25,10,10"
                       FontAttributes="Bold"
                       FontSize="18"
                       HorizontalOptions="Fill"
                       HorizontalTextAlignment="Center" />
                <Label Text="Try a broader filter?"
                       FontAttributes="Italic"
                       FontSize="12"
                       HorizontalOptions="Fill"
                       HorizontalTextAlignment="Center" />
            </StackLayout>
        </ContentView>
    </ContentPage.Resources>

    <StackLayout Margin="20">
        <SearchBar x:Name="searchBar"
                   SearchCommand="{Binding FilterCommand}"
                   SearchCommandParameter="{Binding Source={x:Reference searchBar}, Path=Text}"
                   Placeholder="Filter" />
        <StackLayout Orientation="Horizontal">
            <Label Text="Toggle EmptyViews" />
            <Switch Toggled="OnEmptyViewSwitchToggled" />
        </StackLayout>
        <CollectionView x:Name="collectionView"
                        ItemsSource="{Binding Monkeys}">
            <CollectionView.ItemTemplate>
                <DataTemplate>
                    ...
                </DataTemplate>
            </CollectionView.ItemTemplate>
        </CollectionView>
    </StackLayout>
</ContentPage>

この XAML は、ページ レベルの ResourceDictionary に 2 つの ContentView オブジェクトを定義します。Switch オブジェクトは、どの ContentView オブジェクトを EmptyView プロパティ値として設定するかを制御します。 Switch が切り替わると、OnEmptyViewSwitchToggled イベント ハンドラーは ToggleEmptyView メソッドを実行します。

void ToggleEmptyView(bool isToggled)
{
    collectionView.EmptyView = isToggled ? Resources["BasicEmptyView"] : Resources["AdvancedEmptyView"];
}

ToggleEmptyView メソッドは、Switch.IsToggled プロパティの値に基づいて、collectionView オブジェクトの EmptyView プロパティを、ResourceDictionary に格納されている 2 つの ContentView オブジェクトのいずれかに設定します。 SearchBarFilterCommand を実行すると、CollectionView で表示されるコレクションが、SearchBar.Text プロパティに格納されている検索語でフィルター処理されます。 フィルタリング操作でデータが得られない場合は、EmptyView プロパティとして設定された ContentView オブジェクトが表示されます。

iOS および Android での、空のビューがスワップされた CollectionView の縦方向リストのスクリーンショット

リソース ディクショナリについて詳しくは、「Xamarin.Forms のリソース ディクショナリ」を参照してください。

実行時に EmptyViewTemplate を選択する

CollectionView.EmptyViewTemplate プロパティを DataTemplateSelector オブジェクトに設定することで、EmptyView の外観を、その値に基づいて実行時に選択できます。

<ContentPage ...
             xmlns:controls="clr-namespace:CollectionViewDemos.Controls">
    <ContentPage.Resources>
        <DataTemplate x:Key="AdvancedTemplate">
            ...
        </DataTemplate>

        <DataTemplate x:Key="BasicTemplate">
            ...
        </DataTemplate>

        <controls:SearchTermDataTemplateSelector x:Key="SearchSelector"
                                                 DefaultTemplate="{StaticResource AdvancedTemplate}"
                                                 OtherTemplate="{StaticResource BasicTemplate}" />
    </ContentPage.Resources>

    <StackLayout Margin="20">
        <SearchBar x:Name="searchBar"
                   SearchCommand="{Binding FilterCommand}"
                   SearchCommandParameter="{Binding Source={x:Reference searchBar}, Path=Text}"
                   Placeholder="Filter" />
        <CollectionView ItemsSource="{Binding Monkeys}"
                        EmptyView="{Binding Source={x:Reference searchBar}, Path=Text}"
                        EmptyViewTemplate="{StaticResource SearchSelector}" />
    </StackLayout>
</ContentPage>

同等の C# コードを次に示します。

SearchBar searchBar = new SearchBar { ... };
CollectionView collectionView = new CollectionView
{
    EmptyView = searchBar.Text,
    EmptyViewTemplate = new SearchTermDataTemplateSelector { ... }
};
collectionView.SetBinding(ItemsView.ItemsSourceProperty, "Monkeys");

EmptyView プロパティは SearchBar.Text プロパティに設定され、EmptyViewTemplate プロパティは SearchTermDataTemplateSelector オブジェクトに設定されます。

SearchBarFilterCommand を実行すると、CollectionView に表示されるコレクションがフィルタリングされて、SearchBar.Text プロパティに格納されている検索語句が取得されます。 フィルタリング操作でデータが得られない場合は、SearchTermDataTemplateSelector オブジェクトで選択された DataTemplateEmptyViewTemplate プロパティとして設定され、表示されます。

次の例は、SearchTermDataTemplateSelector クラスを示しています。

public class SearchTermDataTemplateSelector : DataTemplateSelector
{
    public DataTemplate DefaultTemplate { get; set; }
    public DataTemplate OtherTemplate { get; set; }

    protected override DataTemplate OnSelectTemplate(object item, BindableObject container)
    {
        string query = (string)item;
        return query.ToLower().Equals("xamarin") ? OtherTemplate : DefaultTemplate;
    }
}

SearchTermTemplateSelector クラスは、異なるデータ テンプレートに設定される DefaultTemplate および OtherTemplate DataTemplate プロパティを定義します。 検索クエリが "xamarin" と等しくない場合、OnSelectTemplate オーバーライドは DefaultTemplate を返し、ユーザーにメッセージが表示されます。 検索クエリが "xamarin" と等しい場合、OnSelectTemplate オーバーライドは OtherTemplate を返し、ユーザーに基本的なメッセージが表示されます。

iOS と Android 上での、CollectionView ランタイム項目テンプレート選択のスクリーンショット

データ テンプレート セレクターについて詳しくは、「Xamarin.Forms DataTemplateSelector の作成」を参照してください。