Xamarin.Forms CarouselView 数据

CarouselView 包括以下用于定义要显示的数据及其外观的属性:

  • ItemsSource,类型为 IEnumerable,指定要显示的项集合,其默认值为 null
  • ItemTemplate,类型为 DataTemplate,指定将应用于要显示的项集合中的各个项的模板。

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

注意

CarouselView 定义 ItemsUpdatingScrollMode 属性,表示 CarouselView 添加新项时的滚动行为。 有关此属性的详细信息,请参阅添加新项时的控件滚动位置

CarouselView 支持在用户滚动时进行增量数据虚拟化。 有关详细信息,请参阅以增量方式加载数据

使用数据填充 CarouselView

通过将 CarouselViewItemsSource 属性设置为实现 IEnumerable 的任何集合来填充数据。 默认情况下,CarouselView 水平显示项。

重要说明

如果在基础集合中添加、移除或更改项时需要刷新 CarouselView,则基础集合应是发送属性更改通知的 IEnumerable 集合,例如 ObservableCollection

通过使用数据绑定将 CarouselViewItemsSource 属性绑定到 IEnumerable 集合即可对其填充数据。 在 XAML 中,此过程可通过使用 Binding 标记扩展实现:

<CarouselView ItemsSource="{Binding Monkeys}" />

等效 C# 代码如下:

CarouselView carouselView = new CarouselView();
carouselView.SetBinding(ItemsView.ItemsSourceProperty, "Monkeys");

在此示例中, ItemsSource 属性数据绑定到所连接视图模型的 Monkeys 属性。

注意

可启用已编译的绑定来提升 Xamarin.Forms 应用程序中的数据绑定性能。 有关详细信息,请参阅已编译的绑定

有关如何更改 CarouselView 方向的信息,请参阅 Xamarin.Forms CarouselView 布局。 有关如何定义 CarouselView 每个项的外观的信息,请参阅定义项外观。 若要深入了解数据绑定,请参阅 Xamarin.Forms 数据绑定

定义项外观

CarouselView.ItemTemplate 属性设置为 DataTemplate 可定义 CarouselView 中每个项的外观:

<CarouselView ItemsSource="{Binding Monkeys}">
    <CarouselView.ItemTemplate>
        <DataTemplate>
            <StackLayout>
                <Frame HasShadow="True"
                       BorderColor="DarkGray"
                       CornerRadius="5"
                       Margin="20"
                       HeightRequest="300"
                       HorizontalOptions="Center"
                       VerticalOptions="CenterAndExpand">
                    <StackLayout>
                        <Label Text="{Binding Name}"
                               FontAttributes="Bold"
                               FontSize="Large"
                               HorizontalOptions="Center"
                               VerticalOptions="Center" />
                        <Image Source="{Binding ImageUrl}"
                               Aspect="AspectFill"
                               HeightRequest="150"
                               WidthRequest="150"
                               HorizontalOptions="Center" />
                        <Label Text="{Binding Location}"
                               HorizontalOptions="Center" />
                        <Label Text="{Binding Details}"
                               FontAttributes="Italic"
                               HorizontalOptions="Center"
                               MaxLines="5"
                               LineBreakMode="TailTruncation" />
                    </StackLayout>
                </Frame>
            </StackLayout>
        </DataTemplate>
    </CarouselView.ItemTemplate>
</CarouselView>

等效 C# 代码如下:

CarouselView carouselView = new CarouselView();
carouselView.SetBinding(ItemsView.ItemsSourceProperty, "Monkeys");

carouselView.ItemTemplate = new DataTemplate(() =>
{
    Label nameLabel = new Label { ... };
    nameLabel.SetBinding(Label.TextProperty, "Name");

    Image image = new Image { ... };
    image.SetBinding(Image.SourceProperty, "ImageUrl");

    Label locationLabel = new Label { ... };
    locationLabel.SetBinding(Label.TextProperty, "Location");

    Label detailsLabel = new Label { ... };
    detailsLabel.SetBinding(Label.TextProperty, "Details");

    StackLayout stackLayout = new StackLayout
    {
        Children = { nameLabel, image, locationLabel, detailsLabel }
    };

    Frame frame = new Frame { ... };
    StackLayout rootStackLayout = new StackLayout
    {
        Children = { frame }
    };

    return rootStackLayout;
});

DataTemplate 中指定的元素定义 CarouselView 中各个项的外观。 在此示例中,DataTemplate 中的布局由 StackLayout 管理,并且数据通过一个 Image 对象和三个 Label 对象显示,这些对象都绑定到 Monkey 类的属性:

public class Monkey
{
    public string Name { get; set; }
    public string Location { get; set; }
    public string Details { get; set; }
    public string ImageUrl { get; set; }
}

下面的屏幕截图显示了每个项模板化后的结果:

iOS 和 Android 上的 CarouselView 的屏幕截图,其中每个项都已模板化

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

在运行时选择项外观

通过将 CarouselView.ItemTemplate 属性设置为 DataTemplateSelector 对象,可以在运行时根据项值选择 CarouselView 中每个项的外观:

<ContentPage ...
             xmlns:controls="clr-namespace:CarouselViewDemos.Controls"
             x:Class="CarouselViewDemos.Views.HorizontalLayoutDataTemplateSelectorPage">
    <ContentPage.Resources>
        <DataTemplate x:Key="AmericanMonkeyTemplate">
            ...
        </DataTemplate>

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

        <controls:MonkeyDataTemplateSelector x:Key="MonkeySelector"
                                             AmericanMonkey="{StaticResource AmericanMonkeyTemplate}"
                                             OtherMonkey="{StaticResource OtherMonkeyTemplate}" />
    </ContentPage.Resources>

    <CarouselView ItemsSource="{Binding Monkeys}"
                  ItemTemplate="{StaticResource MonkeySelector}" />
</ContentPage>

等效 C# 代码如下:

CarouselView carouselView = new CarouselView
{
    ItemTemplate = new MonkeyDataTemplateSelector { ... }
};
carouselView.SetBinding(ItemsView.ItemsSourceProperty, "Monkeys");

ItemTemplate 属性设置为 MonkeyDataTemplateSelector 对象。 以下示例显示了 MonkeyDataTemplateSelector 类:

public class MonkeyDataTemplateSelector : DataTemplateSelector
{
    public DataTemplate AmericanMonkey { get; set; }
    public DataTemplate OtherMonkey { get; set; }

    protected override DataTemplate OnSelectTemplate(object item, BindableObject container)
    {
        return ((Monkey)item).Location.Contains("America") ? AmericanMonkey : OtherMonkey;
    }
}

MonkeyDataTemplateSelector 类定义 AmericanMonkeyOtherMonkeyDataTemplate 属性,这两个属性设置为不同的数据模板。 当猴子名称包含“America”时,OnSelectTemplate 替代将返回 AmericanMonkey 模板。 当猴子名称不包含“America”时,OnSelectTemplate 替代将返回 OtherMonkey 模板,该模板将其数据显示为灰色:

iOS 和 Android 上 CarouselView 运行时项模板选择的屏幕截图

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

重要说明

使用 CarouselView 时,切勿将 DataTemplate 对象的根元素设置为 ViewCell。 这将导致引发异常,因为 CarouselView 没有单元格的概念。

显示指示器

可在 CarouselView 旁边显示表示 CarouselView 中的项数和当前位置的指示器。 这可以通过 IndicatorView 控件来实现:

<StackLayout>
    <CarouselView ItemsSource="{Binding Monkeys}"
                  IndicatorView="indicatorView">
        <CarouselView.ItemTemplate>
            <!-- DataTemplate that defines item appearance -->
        </CarouselView.ItemTemplate>
    </CarouselView>
    <IndicatorView x:Name="indicatorView"
                   IndicatorColor="LightGray"
                   SelectedIndicatorColor="DarkGray"
                   HorizontalOptions="Center" />
</StackLayout>

在此示例中,IndicatorView 呈现在 CarouselView 下方,其中包含 CarouselView 中每个项的指示器。 IndicatorView 通过将 CarouselView.IndicatorView 属性设置为 IndicatorView 对象来填充数据。 每个指示器都是浅灰色圆圈,而表示 CarouselView 中当前项的指示器为深灰色:

iOS 和 Android 上 CarouselView 和 IndicatorView 的屏幕截图

重要

设置 CarouselView.IndicatorView 属性会导致 IndicatorView.Position 属性绑定到 CarouselView.Position 属性,且 IndicatorView.ItemsSource 属性绑定到 CarouselView.ItemsSource 属性。

有关指示器的详细信息,请参阅 Xamarin.Forms IndicatorView

上下文菜单

CarouselView 支持通过 SwipeView 查看上下文菜单的数据项,此控件通过轻扫手势显示上下文菜单。 SwipeView 是一个容器控件,该控件包围内容项,并为该内容项提供上下文菜单项。 因此,通过创建 SwipeView 并定义 SwipeView 包围的内容以及通过轻扫手势显示的上下文菜单项,可以针对 CarouselView 实现上下文菜单。 实现方法就是将 SwipeView 添加到 DataTemplate 以定义 CarouselView 中各数据项的外观:

<CarouselView x:Name="carouselView"
              ItemsSource="{Binding Monkeys}">
    <CarouselView.ItemTemplate>
        <DataTemplate>
            <StackLayout>
                    <Frame HasShadow="True"
                           BorderColor="DarkGray"
                           CornerRadius="5"
                           Margin="20"
                           HeightRequest="300"
                           HorizontalOptions="Center"
                           VerticalOptions="CenterAndExpand">
                        <SwipeView>
                            <SwipeView.TopItems>
                                <SwipeItems>
                                    <SwipeItem Text="Favorite"
                                               IconImageSource="favorite.png"
                                               BackgroundColor="LightGreen"
                                               Command="{Binding Source={x:Reference carouselView}, Path=BindingContext.FavoriteCommand}"
                                               CommandParameter="{Binding}" />
                                </SwipeItems>
                            </SwipeView.TopItems>
                            <SwipeView.BottomItems>
                                <SwipeItems>
                                    <SwipeItem Text="Delete"
                                               IconImageSource="delete.png"
                                               BackgroundColor="LightPink"
                                               Command="{Binding Source={x:Reference carouselView}, Path=BindingContext.DeleteCommand}"
                                               CommandParameter="{Binding}" />
                                </SwipeItems>
                            </SwipeView.BottomItems>
                            <StackLayout>
                                <!-- Define item appearance -->
                            </StackLayout>
                        </SwipeView>
                    </Frame>
            </StackLayout>
        </DataTemplate>
    </CarouselView.ItemTemplate>
</CarouselView>

等效 C# 代码如下:

CarouselView carouselView = new CarouselView();
carouselView.SetBinding(ItemsView.ItemsSourceProperty, "Monkeys");

carouselView.ItemTemplate = new DataTemplate(() =>
{
    StackLayout stackLayout = new StackLayout();
    Frame frame = new Frame { ... };

    SwipeView swipeView = new SwipeView();
    SwipeItem favoriteSwipeItem = new SwipeItem
    {
        Text = "Favorite",
        IconImageSource = "favorite.png",
        BackgroundColor = Color.LightGreen
    };
    favoriteSwipeItem.SetBinding(MenuItem.CommandProperty, new Binding("BindingContext.FavoriteCommand", source: carouselView));
    favoriteSwipeItem.SetBinding(MenuItem.CommandParameterProperty, ".");

    SwipeItem deleteSwipeItem = new SwipeItem
    {
        Text = "Delete",
        IconImageSource = "delete.png",
        BackgroundColor = Color.LightPink
    };
    deleteSwipeItem.SetBinding(MenuItem.CommandProperty, new Binding("BindingContext.DeleteCommand", source: carouselView));
    deleteSwipeItem.SetBinding(MenuItem.CommandParameterProperty, ".");

    swipeView.TopItems = new SwipeItems { favoriteSwipeItem };
    swipeView.BottomItems = new SwipeItems { deleteSwipeItem };

    StackLayout swipeViewStackLayout = new StackLayout { ... };
    swipeView.Content = swipeViewStackLayout;
    frame.Content = swipeView;
    stackLayout.Children.Add(frame);

    return stackLayout;
});

在此示例中, SwipeView 内容是一个 StackLayout,用于定义 CarouselView 中由 Frame 包围的每个项的外观。 轻扫项用于对 SwipeView 内容执行操作,它们在从顶部和底部轻扫控件时显示:

iOS 和 Android 上 CarouselView 底部上下文菜单项的屏幕截图iOS 和 Android 上 CarouselView 顶部菜单项的屏幕截图

SwipeView 支持四个不同的轻扫方向,并且轻扫方向由添加 SwipeItems 对象的 SwipeItems 方向集合定义。 默认情况下,轻扫项会在用户点击时执行。 此外,执行某个轻扫项后,该轻扫项将会隐藏,并重新显示 SwipeView 内容。 但是,此类行为可以更改。

有关 SwipeView 控件的详细信息,请参阅 Xamarin.Forms SwipeView

下拉以刷新

CarouselView 支持通过 RefreshView 实现下拉以刷新功能,此控件允许通过向下拉动项来刷新要显示的数据。 RefreshView 是一个容器控件,该控件可为其子级提供下拉以刷新功能,前提是该子级支持可滚动内容。 因此,通过将 CarouselView 设置为 RefreshView 的子级可实现其下拉以刷新功能:

<RefreshView IsRefreshing="{Binding IsRefreshing}"
             Command="{Binding RefreshCommand}">
    <CarouselView ItemsSource="{Binding Animals}">
        ...
    </CarouselView>
</RefreshView>

等效 C# 代码如下:

RefreshView refreshView = new RefreshView();
ICommand refreshCommand = new Command(() =>
{
    // IsRefreshing is true
    // Refresh data here
    refreshView.IsRefreshing = false;
});
refreshView.Command = refreshCommand;

CarouselView carouselView = new CarouselView();
carouselView.SetBinding(ItemsView.ItemsSourceProperty, "Animals");
refreshView.Content = carouselView;
// ...

当用户启动刷新时,将执行由 Command 属性定义的 ICommand,这将刷新所显示的项。 刷新时会显示刷新可视化效果,其中包含动画形式的圆形进度:

iOS 和 Android 上 CarouselView 下拉以刷新的屏幕截图

RefreshView.IsRefreshing 属性的值指示 RefreshView 的当前状态。 当用户触发刷新时,此属性将自动转换为 true。 刷新完成后,应将该属性重置为 false

有关 RefreshView 的详细信息,请参阅 Xamarin.Forms RefreshView

以增量方式加载数据

CarouselView 支持在用户滚动时进行增量数据虚拟化。 这可实现诸如在用户滚动时从 Web 服务异步加载数据页等方案。 此外,加载更多数据的点是可配置的,这样用户就看不到空白,也不会停止滚动。

CarouselView 定义下列属性,用于控制数据的增量加载:

  • RemainingItemsThreshold,类型为 int,列表中尚不可见的项的阈值,达到此阈值时将触发 RemainingItemsThresholdReached 事件。
  • RemainingItemsThresholdReachedCommand,类型为 ICommand,达到 RemainingItemsThreshold 时就会执行。
  • RemainingItemsThresholdReachedCommandParameter 属于 object 类型,是传递给 RemainingItemsThresholdReachedCommand 的参数。

CarouselView 还会定义一个 RemainingItemsThresholdReached 事件,当 CarouselView 滚动得足够远,直到尚未显示 RemainingItemsThreshold 项时,将触发该事件。 可以处理此事件以加载更多项。 此外,在触发 RemainingItemsThresholdReached 事件时,将执行 RemainingItemsThresholdReachedCommand,从而在视图模型中增量加载数据。

RemainingItemsThreshold 属性的默认值为 -1,指示永远不会触发 RemainingItemsThresholdReached 事件。 当属性值为 0 时,将在显示 ItemsSource 中的最后一项时触发 RemainingItemsThresholdReached 事件。 对于大于 0 的值,当 ItemsSource 包含尚未滚动到的项数时将触发 RemainingItemsThresholdReached 事件。

注意

CarouselView 用于验证 RemainingItemsThreshold 属性,使该属性的值始终大于或等于 -1。

下面的 XAML 示例显示了以增量方式加载数据的 CarouselView

<CarouselView ItemsSource="{Binding Animals}"
              RemainingItemsThreshold="2"
              RemainingItemsThresholdReached="OnCarouselViewRemainingItemsThresholdReached"
              RemainingItemsThresholdReachedCommand="{Binding LoadMoreDataCommand}">
    ...
</CarouselView>

等效 C# 代码如下:

CarouselView carouselView = new CarouselView
{
    RemainingItemsThreshold = 2
};
carouselView.RemainingItemsThresholdReached += OnCollectionViewRemainingItemsThresholdReached;
carouselView.SetBinding(ItemsView.ItemsSourceProperty, "Animals");

在此代码示例中,当有 2 个项尚未滚动到时将触发 RemainingItemsThresholdReached 事件,而响应措施是执行 OnCollectionViewRemainingItemsThresholdReached 事件处理程序:

void OnCollectionViewRemainingItemsThresholdReached(object sender, EventArgs e)
{
    // Retrieve more data here and add it to the CollectionView's ItemsSource collection.
}

注意

还可以通过在视图模型中将 RemainingItemsThresholdReachedCommand 绑定到 ICommand 实现,以增量方式加载数据。