Xamarin.Forms CarouselView EmptyView

CarouselView 定义了以下属性,这些属性可用于在没有要显示的数据时提供用户反馈:

  • EmptyView,类型为 object,是指当 ItemsSource 属性为 null 时或当 ItemsSource 属性指定的集合为 null 或为空时,将显示的字符串、绑定或视图。 默认值为 null
  • EmptyViewTemplate,类型为 DataTemplate,用于对指定 EmptyView 设置格式的模板。 默认值为 null

所有这些属性都由 BindableProperty 对象提供支持,这意味着这些属性可以作为数据绑定的目标。

设置 EmptyView 属性的主要使用场景是,在对 CarouselView 执行筛选操作后没有获得数据时显示用户反馈,以及在从 Web 服务检索数据时显示用户反馈。

注意

如果需要,可将 EmptyView 属性设置为包含交互式内容的视图。

有关数据模板的详细信息,请参阅 Xamarin.Forms 数据模板

当数据不可用时显示字符串

EmptyView 属性可设置为字符串,当 ItemsSource 属性为 null 时,或当 ItemsSource 属性指定的集合为 null 或为空时,将显示该字符串。 以下 XAML 显示了此方案的示例:

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

等效 C# 代码如下:

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

结果是,由于数据绑定集合是 null,因此会显示设置为 EmptyView 属性值的字符串。

当数据不可用时显示视图

EmptyView 属性可设置为视图,当 ItemsSource 属性为 null 时,或 ItemsSource 属性指定的集合为 null 或为空时,将显示该视图。 这可以是单个视图,也可以是包含多个子视图的视图。 以下 XAML 示例显示了将 EmptyView 属性设置为包含多个子视图的视图:

<StackLayout Margin="20">
    <SearchBar SearchCommand="{Binding FilterCommand}"
               SearchCommandParameter="{Binding Source={RelativeSource Self}, Path=Text}"
               Placeholder="Filter" />
    <CarouselView ItemsSource="{Binding Monkeys}">
        <CarouselView.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>
        </CarouselView.EmptyView>
        <CarouselView.ItemTemplate>
            ...
        </CarouselView.ItemTemplate>
    </CarouselView>
</StackLayout>

在此示例中,已将看起来像是冗余的 ContentView 添加为 EmptyView 的根元素。 这是因为,在内部 EmptyView 会添加到不为 Xamarin.Forms 布局提供任何上下文的一个原生容器。 因此,要定位构成 EmptyView 的视图,必须添加根布局,而根布局的子布局可以在根布局中定位。

等效 C# 代码如下:

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

SearchBar 执行 FilterCommand 时,将对 CarouselView 显示的集合进行筛选,以查找存储在 SearchBar.Text 属性中的搜索词。 如果筛选操作不生成任何数据,则会显示设置为 EmptyView 属性值的 StackLayout

当数据不可用时显示模板化的自定义类型

EmptyView 属性可设置为自定义类型,当 ItemsSource 属性为 null 时,或当 ItemsSource 属性指定的集合为 null 或为空时,将显示其模板。 EmptyViewTemplate 属性可设置为定义 EmptyView 外观的 DataTemplate。 以下 XAML 显示了此方案的示例:

<StackLayout Margin="20">
    <SearchBar x:Name="searchBar"
               SearchCommand="{Binding FilterCommand}"
               SearchCommandParameter="{Binding Source={RelativeSource Self}, Path=Text}"
               Placeholder="Filter" />
    <CarouselView ItemsSource="{Binding Monkeys}">
        <CarouselView.EmptyView>
            <controls:FilterData Filter="{Binding Source={x:Reference searchBar}, Path=Text}" />
        </CarouselView.EmptyView>
        <CarouselView.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>
        </CarouselView.EmptyViewTemplate>
        <CarouselView.ItemTemplate>
            ...
        </CarouselView.ItemTemplate>
    </CarouselView>
</StackLayout>

等效 C# 代码如下:

SearchBar searchBar = new SearchBar { ... };
CarouselView carouselView = new CarouselView
{
    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 属性。 当 SearchBar 执行 FilterCommand 时,将对 CarouselView 显示的集合进行筛选,以查找存储在 Filter 属性中的搜索词。 如果筛选操作不生成任何数据,则会显示 DataTemplate 中定义的 Label 并将其设置为 EmptyViewTemplate 属性值。

注意

当数据不可用时显示模板化自定义类型时,可将 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"
             xmlns:viewmodels="clr-namespace:CarouselViewDemos.ViewModels"
             x:Class="CarouselViewDemos.Views.EmptyViewSwapPage"
             Title="EmptyView (swap)">
    <ContentPage.BindingContext>
        <viewmodels:MonkeysViewModel />
    </ContentPage.BindingContext>
    <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 SearchCommand="{Binding FilterCommand}"
                   SearchCommandParameter="{Binding Source={RelativeSource Self}, Path=Text}"
                   Placeholder="Filter" />
        <StackLayout Orientation="Horizontal">
            <Label Text="Toggle EmptyViews" />
            <Switch Toggled="OnEmptyViewSwitchToggled" />
        </StackLayout>
        <CarouselView x:Name="carouselView"
                      ItemsSource="{Binding Monkeys}">
            <CarouselView.ItemTemplate>
                ...
            </CarouselView.ItemTemplate>
        </CarouselView>
    </StackLayout>
</ContentPage>

此 XAML 在页面级 ResourceDictionary 中定义两个 ContentView 对象,其中 Switch 对象控制将哪个 ContentView 对象设置为 EmptyView 属性值。 切换 Switch 时,OnEmptyViewSwitchToggled 事件处理程序会执行 ToggleEmptyView 方法:

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

ToggleEmptyView 方法根据 Switch.IsToggled 属性的值,将 carouselView 对象的 EmptyView 属性设置为 ResourceDictionary 中存储的两个 ContentView 对象之一。 当 SearchBar 执行 FilterCommand 时,将对 CarouselView 显示的集合进行筛选,以查找存储在 SearchBar.Text 属性中的搜索词。 如果筛选操作不生成任何数据,则会显示设置为 EmptyView 属性的 ContentView 对象。

有关资源字典的详细信息,请参阅 Xamarin.Forms 资源字典

在运行时选择 EmptyViewTemplate

通过将 CarouselView.EmptyViewTemplate 属性设置为 DataTemplateSelector 对象,可以在运行时根据 EmptyView 的值选择其外观:

<ContentPage ...
             xmlns:controls="clr-namespace:CarouselViewDemos.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={RelativeSource Self}, Path=Text}"
                   Placeholder="Filter" />
        <CarouselView ItemsSource="{Binding Monkeys}"
                      EmptyView="{Binding Source={x:Reference searchBar}, Path=Text}"
                      EmptyViewTemplate="{StaticResource SearchSelector}">
            <CarouselView.ItemTemplate>
                ...
            </CarouselView.ItemTemplate>
        </CarouselView>
    </StackLayout>
</ContentPage>

等效 C# 代码如下:

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

EmptyView 属性设置为 SearchBar.Text 属性,并且 EmptyViewTemplate 属性设置为 SearchTermDataTemplateSelector 对象。

SearchBar 执行 FilterCommand 时,将对 CarouselView 显示的集合进行筛选,以查找存储在 SearchBar.Text 属性中的搜索词。 如果筛选操作没有产生任何数据,则会将由 SearchTermDataTemplateSelector 对象的选择的 DataTemplate 设置为 EmptyViewTemplate 属性并显示。

以下示例显示了 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 类定义设置为不同数据模板的 DefaultTemplateOtherTemplateDataTemplate 属性。 OnSelectTemplate 替代会返回 DefaultTemplate,当搜索查询不等于 "xamarin" 时,它会向用户显示消息。 当搜索查询等于 "xamarin" 时,则 OnSelectTemplate 替代返回 OtherTemplate,这会向用户显示基本消息。

有关数据模板选择器的详细信息,请参阅创建 Xamarin.Forms DataTemplateSelector