Xamarin.Forms CollectionView 数据
CollectionView
包括以下用于定义要显示的数据及其外观的属性:
ItemsSource
,类型为IEnumerable
,指定要显示的项集合,其默认值为null
。ItemTemplate
,类型为DataTemplate
,指定将应用于要显示的项集合中的各个项的模板。
这些属性由 BindableProperty
对象提供支持,这意味着这些属性可以作为数据绑定的目标。
注意
CollectionView
定义 ItemsUpdatingScrollMode
属性,表示 CollectionView
添加新项时的滚动行为。 有关此属性的详细信息,请参阅添加新项时的控件滚动位置。
CollectionView
支持在用户滚动时进行增量数据虚拟化。 有关详细信息,请参阅以增量方式加载数据。
使用数据填充 CollectionView
通过将 CollectionView
的 ItemsSource
属性设置为实现 IEnumerable
的任何集合来为其填充数据。 默认情况下,CollectionView
在垂直列表中显示项。
重要
如果在基础集合中添加、移除或更改项时需要刷新 CollectionView
,则基础集合应是发送属性更改通知的 IEnumerable
集合,例如 ObservableCollection
。
通过使用数据绑定将 CollectionView
的 ItemsSource
属性绑定到 IEnumerable
集合即可对其填充数据。 在 XAML 中,此过程可通过使用 Binding
标记扩展实现:
<CollectionView ItemsSource="{Binding Monkeys}" />
等效 C# 代码如下:
CollectionView collectionView = new CollectionView();
collectionView.SetBinding(ItemsView.ItemsSourceProperty, "Monkeys");
在此示例中, ItemsSource
属性数据绑定到所连接视图模型的 Monkeys
属性。
注意
可启用已编译的绑定来提升 Xamarin.Forms 应用程序中的数据绑定性能。 有关详细信息,请参阅已编译的绑定。
有关如何更改 CollectionView
布局的信息,请参阅 Xamarin.Forms CollectionView 布局。 有关如何定义 CollectionView
每个项的外观的信息,请参阅定义项外观。 若要深入了解数据绑定,请参阅 Xamarin.Forms 数据绑定。
警告
如果 ItemsSource
在 UI 线程之外更新,CollectionView
将触发异常。
定义项外观
将 CollectionView.ItemTemplate
属性设置为 DataTemplate
可定义 CollectionView
中每个项的外观:
<CollectionView ItemsSource="{Binding Monkeys}">
<CollectionView.ItemTemplate>
<DataTemplate>
<Grid Padding="10">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Image Grid.RowSpan="2"
Source="{Binding ImageUrl}"
Aspect="AspectFill"
HeightRequest="60"
WidthRequest="60" />
<Label Grid.Column="1"
Text="{Binding Name}"
FontAttributes="Bold" />
<Label Grid.Row="1"
Grid.Column="1"
Text="{Binding Location}"
FontAttributes="Italic"
VerticalOptions="End" />
</Grid>
</DataTemplate>
</CollectionView.ItemTemplate>
...
</CollectionView>
等效 C# 代码如下:
CollectionView collectionView = new CollectionView();
collectionView.SetBinding(ItemsView.ItemsSourceProperty, "Monkeys");
collectionView.ItemTemplate = new DataTemplate(() =>
{
Grid grid = new Grid { Padding = 10 };
grid.RowDefinitions.Add(new RowDefinition { Height = GridLength.Auto });
grid.RowDefinitions.Add(new RowDefinition { Height = GridLength.Auto });
grid.ColumnDefinitions.Add(new ColumnDefinition { Width = GridLength.Auto });
grid.ColumnDefinitions.Add(new ColumnDefinition { Width = GridLength.Auto });
Image image = new Image { Aspect = Aspect.AspectFill, HeightRequest = 60, WidthRequest = 60 };
image.SetBinding(Image.SourceProperty, "ImageUrl");
Label nameLabel = new Label { FontAttributes = FontAttributes.Bold };
nameLabel.SetBinding(Label.TextProperty, "Name");
Label locationLabel = new Label { FontAttributes = FontAttributes.Italic, VerticalOptions = LayoutOptions.End };
locationLabel.SetBinding(Label.TextProperty, "Location");
Grid.SetRowSpan(image, 2);
grid.Children.Add(image);
grid.Children.Add(nameLabel, 1, 0);
grid.Children.Add(locationLabel, 1, 1);
return grid;
});
DataTemplate
中指定的元素定义列表中各个项的外观。 在此示例中,DataTemplate
的内部布局由 Grid
管理。 Grid
包含一个 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; }
}
下面的屏幕截图显示了列表中每个项模板化后的结果:
有关数据模板的详细信息,请参阅 Xamarin.Forms 数据模板。
在运行时选择项外观
通过将 CollectionView.ItemTemplate
属性设置为 DataTemplateSelector
对象,可以在运行时根据项值选择 CollectionView
中每个项的外观:
<ContentPage ...
xmlns:controls="clr-namespace:CollectionViewDemos.Controls">
<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>
<CollectionView ItemsSource="{Binding Monkeys}"
ItemTemplate="{StaticResource MonkeySelector}" />
</ContentPage>
等效 C# 代码如下:
CollectionView collectionView = new CollectionView
{
ItemTemplate = new MonkeyDataTemplateSelector { ... }
};
collectionView.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
类定义 AmericanMonkey
和 OtherMonkey
DataTemplate
属性,这些属性设置为不同的数据模板。 当猴子名称包含“美国”时,OnSelectTemplate
重写函数会返回 AmericanMonkey
模板,该模板以青色显示猴子名称和位置。 当猴子名称中不包含“美国”时,OnSelectTemplate
重写函数将返回 OtherMonkey
模板,该模板以银色显示猴子名称和位置:
有关数据模板选择器的详细信息,请参阅创建 Xamarin.Forms DataTemplateSelector。
重要说明
使用 CollectionView
时,切勿将 DataTemplate
对象的根元素设置为 ViewCell
。 这将引发异常,因为 CollectionView
没有单元格的概念。
上下文菜单
CollectionView
支持通过 SwipeView
查看上下文菜单的数据项,此控件通过轻扫手势显示上下文菜单。 SwipeView
是一个容器控件,该控件包围内容项,并为该内容项提供上下文菜单项。 因此,上下文菜单是通过创建用于定义 SwipeView
所围绕内容以及轻扫手势所显示上下文菜单项的 SwipeView
,针对 CollectionView
实现的。 这可通过将 SwipeView
设置为 DataTemplate
中的根视图实现,该视图用于定义 CollectionView
中各数据项的外观:
<CollectionView x:Name="collectionView"
ItemsSource="{Binding Monkeys}">
<CollectionView.ItemTemplate>
<DataTemplate>
<SwipeView>
<SwipeView.LeftItems>
<SwipeItems>
<SwipeItem Text="Favorite"
IconImageSource="favorite.png"
BackgroundColor="LightGreen"
Command="{Binding Source={x:Reference collectionView}, Path=BindingContext.FavoriteCommand}"
CommandParameter="{Binding}" />
<SwipeItem Text="Delete"
IconImageSource="delete.png"
BackgroundColor="LightPink"
Command="{Binding Source={x:Reference collectionView}, Path=BindingContext.DeleteCommand}"
CommandParameter="{Binding}" />
</SwipeItems>
</SwipeView.LeftItems>
<Grid BackgroundColor="White"
Padding="10">
<!-- Define item appearance -->
</Grid>
</SwipeView>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
等效 C# 代码如下:
CollectionView collectionView = new CollectionView();
collectionView.SetBinding(ItemsView.ItemsSourceProperty, "Monkeys");
collectionView.ItemTemplate = new DataTemplate(() =>
{
// Define item appearance
Grid grid = new Grid { Padding = 10, BackgroundColor = Color.White };
// ...
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: collectionView));
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: collectionView));
deleteSwipeItem.SetBinding(MenuItem.CommandParameterProperty, ".");
swipeView.LeftItems = new SwipeItems { favoriteSwipeItem, deleteSwipeItem };
swipeView.Content = grid;
return swipeView;
});
在此示例中,SwipeView
内容为定义 CollectionView
中各项外观的 Grid
。 轻扫项用于对 SwipeView
内容执行操作,并在控件从左侧轻扫时显示:
SwipeView
支持四个不同的轻扫方向,并且轻扫方向由添加 SwipeItems
对象的 SwipeItems
方向集合定义。 默认情况下,轻扫项会在用户点击时执行。 此外,执行某个轻扫项后,该轻扫项将会隐藏,并重新显示 SwipeView
内容。 但是,此类行为可以更改。
有关 SwipeView
控件的详细信息,请参阅 Xamarin.Forms SwipeView。
下拉以刷新
CollectionView
支持通过 RefreshView
实现下拉刷新功能,通过向下拉动项列表,可刷新显示的数据。 RefreshView
是一个容器控件,如果其子控件支持可滚动内容,则该控件可为其子控件提供下拉以刷新功能。 因此,通过将 CollectionView
设置为 RefreshView
的子级可实现其下拉以刷新功能:
<RefreshView IsRefreshing="{Binding IsRefreshing}"
Command="{Binding RefreshCommand}">
<CollectionView ItemsSource="{Binding Animals}">
...
</CollectionView>
</RefreshView>
等效 C# 代码如下:
RefreshView refreshView = new RefreshView();
ICommand refreshCommand = new Command(() =>
{
// IsRefreshing is true
// Refresh data here
refreshView.IsRefreshing = false;
});
refreshView.Command = refreshCommand;
CollectionView collectionView = new CollectionView();
collectionView.SetBinding(ItemsView.ItemsSourceProperty, "Animals");
refreshView.Content = collectionView;
// ...
当用户启动刷新时,将执行由 Command
属性定义的 ICommand
,这将刷新所显示的项。 刷新时会显示刷新可视化效果,其中包含动画形式的圆形进度:
RefreshView.IsRefreshing
属性的值指示 RefreshView
的当前状态。 当用户触发刷新时,此属性将自动转换为 true
。 刷新完成后,应将该属性重置为 false
。
有关 RefreshView
的详细信息,请参阅 Xamarin.Forms RefreshView。
以增量方式加载数据
CollectionView
支持在用户滚动时进行增量数据虚拟化。 这可实现诸如在用户滚动时从 Web 服务异步加载数据页等方案。 此外,加载更多数据的点是可配置的,这样用户就看不到空白,也不会停止滚动。
CollectionView
定义下列属性,用于控制数据的增量加载:
RemainingItemsThreshold
,类型为int
,列表中尚不可见的项的阈值,达到此阈值时将触发RemainingItemsThresholdReached
事件。RemainingItemsThresholdReachedCommand
,类型为ICommand
,达到RemainingItemsThreshold
时就会执行。RemainingItemsThresholdReachedCommandParameter
属于object
类型,是传递给RemainingItemsThresholdReachedCommand
的参数。
CollectionView
还会定义一个 RemainingItemsThresholdReached
事件,当 CollectionView
滚动得足够远,直到尚未显示 RemainingItemsThreshold
项时,将触发该事件。 可以处理此事件以加载更多项。 此外,在触发 RemainingItemsThresholdReached
事件时,将执行 RemainingItemsThresholdReachedCommand
,从而在视图模型中增量加载数据。
RemainingItemsThreshold
属性的默认值为 -1,指示永远不会触发 RemainingItemsThresholdReached
事件。 当属性值为 0 时,将在显示 ItemsSource
中的最后一项时触发 RemainingItemsThresholdReached
事件。 对于大于 0 的值,当 ItemsSource
包含尚未滚动到的项数时将触发 RemainingItemsThresholdReached
事件。
注意
CollectionView
用于验证 RemainingItemsThreshold
属性,使该属性的值始终大于或等于 -1。
下面的 XAML 示例显示了以增量方式加载数据的 CollectionView
:
<CollectionView ItemsSource="{Binding Animals}"
RemainingItemsThreshold="5"
RemainingItemsThresholdReached="OnCollectionViewRemainingItemsThresholdReached">
...
</CollectionView>
等效 C# 代码如下:
CollectionView collectionView = new CollectionView
{
RemainingItemsThreshold = 5
};
collectionView.RemainingItemsThresholdReached += OnCollectionViewRemainingItemsThresholdReached;
collectionView.SetBinding(ItemsView.ItemsSourceProperty, "Animals");
在此代码示例中,RemainingItemsThresholdReached
事件在有 5 个项尚未滚动到时触发,并响应执行 OnCollectionViewRemainingItemsThresholdReached
事件处理程序:
void OnCollectionViewRemainingItemsThresholdReached(object sender, EventArgs e)
{
// Retrieve more data here and add it to the CollectionView's ItemsSource collection.
}
注意
还可以通过在视图模型中将 RemainingItemsThresholdReachedCommand
绑定到 ICommand
实现,以增量方式加载数据。