maui-collectionview
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseCollectionView — .NET MAUI
CollectionView — .NET MAUI
CollectionViewListViewViewCellCollectionViewListViewViewCellWhen to Use
适用场景
- Displaying a scrollable list or grid of data items
- Binding a collection of objects to a templated item layout
- Adding selection (single or multiple), grouping, or pull-to-refresh
- Implementing infinite scroll / incremental loading
- Showing swipe actions on list items
- Displaying an empty state when no data is available
- 展示可滚动的数据列表或网格
- 将对象集合绑定到带模板的项布局
- 添加选择(单选或多选)、分组或下拉刷新功能
- 实现无限滚动/增量加载
- 为列表项添加滑动操作
- 无数据时展示空状态
When Not to Use
不适用场景
- Static layouts with a fixed number of items — use or
GriddirectlyStackLayout - Map pin lists — use the NuGet package
Microsoft.Maui.Controls.Maps - Table-based data entry forms — use standard form controls
- Simple text-only lists with no interaction — consider on a
BindableLayoutStackLayout
- 固定数量项的静态布局——直接使用或
GridStackLayout - 地图标记列表——使用NuGet包
Microsoft.Maui.Controls.Maps - 基于表格的数据输入表单——使用标准表单控件
- 无交互的纯文本简单列表——考虑在上使用
StackLayoutBindableLayout
Inputs
输入项
- A data source (typically ) bound to
ObservableCollection<T>ItemsSource - A defining how each item renders
DataTemplate - Optional: layout configuration, selection mode, grouping model, empty view
- 绑定到的数据源(通常为
ItemsSource)ObservableCollection<T> - 定义每个项渲染方式的
DataTemplate - 可选:布局配置、选择模式、分组模型、空视图
Basic Setup
基础设置
xml
<CollectionView ItemsSource="{Binding Items}">
<CollectionView.ItemTemplate>
<DataTemplate x:DataType="models:Item">
<HorizontalStackLayout Padding="8" Spacing="8">
<Image Source="{Binding Icon}" WidthRequest="40" HeightRequest="40" />
<Label Text="{Binding Name}" VerticalOptions="Center" />
</HorizontalStackLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>Key rules:
- Bind to an
ItemsSourceso the UI updates on add/remove.ObservableCollection<T> - Each item template root must be a or
Layout— never useView.ViewCell - Always set on
x:DataTypefor compiled bindings.DataTemplate
xml
<CollectionView ItemsSource="{Binding Items}">
<CollectionView.ItemTemplate>
<DataTemplate x:DataType="models:Item">
<HorizontalStackLayout Padding="8" Spacing="8">
<Image Source="{Binding Icon}" WidthRequest="40" HeightRequest="40" />
<Label Text="{Binding Name}" VerticalOptions="Center" />
</HorizontalStackLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>核心规则:
- 将绑定到
ItemsSource,以便在添加/移除项时自动更新UI。ObservableCollection<T> - 每个项模板的根元素必须是或
Layout——切勿使用View。ViewCell - 始终为设置
DataTemplate以启用编译绑定。x:DataType
Layouts
布局设置
Set to control arrangement. Default is .
ItemsLayoutVerticalList| Layout | XAML value |
|---|---|
| Vertical list | |
| Horizontal list | |
| Vertical grid | |
| Horizontal grid | |
设置来控制项的排列方式,默认值为。
ItemsLayoutVerticalList| 布局类型 | XAML 值 |
|---|---|
| 垂直列表 | |
| 水平列表 | |
| 垂直网格 | |
| 水平网格 | |
Grid Layout
网格布局
xml
<CollectionView ItemsSource="{Binding Items}">
<CollectionView.ItemsLayout>
<GridItemsLayout Orientation="Vertical"
Span="2"
VerticalItemSpacing="8"
HorizontalItemSpacing="8" />
</CollectionView.ItemsLayout>
<CollectionView.ItemTemplate>
<DataTemplate x:DataType="models:Item">
<Border Padding="8" StrokeThickness="0">
<VerticalStackLayout>
<Image Source="{Binding Image}" HeightRequest="120" Aspect="AspectFill" />
<Label Text="{Binding Name}" FontAttributes="Bold" />
</VerticalStackLayout>
</Border>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>xml
<CollectionView ItemsSource="{Binding Items}">
<CollectionView.ItemsLayout>
<GridItemsLayout Orientation="Vertical"
Span="2"
VerticalItemSpacing="8"
HorizontalItemSpacing="8" />
</CollectionView.ItemsLayout>
<CollectionView.ItemTemplate>
<DataTemplate x:DataType="models:Item">
<Border Padding="8" StrokeThickness="0">
<VerticalStackLayout>
<Image Source="{Binding Image}" HeightRequest="120" Aspect="AspectFill" />
<Label Text="{Binding Name}" FontAttributes="Bold" />
</VerticalStackLayout>
</Border>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>Horizontal List
水平列表
xml
<CollectionView ItemsSource="{Binding Items}"
ItemsLayout="HorizontalList" />xml
<CollectionView ItemsSource="{Binding Items}"
ItemsLayout="HorizontalList" />Selection
选择功能
Selection Mode
选择模式
| Mode | Property to bind | Binding mode |
|---|---|---|
| — | — |
| | |
| | |
xml
<CollectionView ItemsSource="{Binding Items}"
SelectionMode="Single"
SelectedItem="{Binding CurrentItem, Mode=TwoWay}"
SelectionChangedCommand="{Binding ItemSelectedCommand}" />For selection, bind (type ):
MultipleSelectedItemsIList<object>xml
<CollectionView SelectionMode="Multiple"
SelectedItems="{Binding ChosenItems, Mode=OneWay}" />| 模式 | 绑定属性 | 绑定模式 |
|---|---|---|
| — | — |
| | |
| | |
xml
<CollectionView ItemsSource="{Binding Items}"
SelectionMode="Single"
SelectedItem="{Binding CurrentItem, Mode=TwoWay}"
SelectionChangedCommand="{Binding ItemSelectedCommand}" />对于多选模式,绑定(类型为):
MultipleSelectedItemsIList<object>xml
<CollectionView SelectionMode="Multiple"
SelectedItems="{Binding ChosenItems, Mode=OneWay}" />Selected Visual State
选中视觉状态
Highlight selected items using :
VisualStateManagerxml
<CollectionView.ItemTemplate>
<DataTemplate x:DataType="models:Item">
<Grid Padding="8">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup Name="CommonStates">
<VisualState Name="Normal">
<VisualState.Setters>
<Setter Property="BackgroundColor" Value="Transparent" />
</VisualState.Setters>
</VisualState>
<VisualState Name="Selected">
<VisualState.Setters>
<Setter Property="BackgroundColor"
Value="{AppThemeBinding Light={StaticResource Primary}, Dark={StaticResource PrimaryDark}}" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Label Text="{Binding Name}" />
</Grid>
</DataTemplate>
</CollectionView.ItemTemplate>使用高亮选中项:
VisualStateManagerxml
<CollectionView.ItemTemplate>
<DataTemplate x:DataType="models:Item">
<Grid Padding="8">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup Name="CommonStates">
<VisualState Name="Normal">
<VisualState.Setters>
<Setter Property="BackgroundColor" Value="Transparent" />
</VisualState.Setters>
</VisualState>
<VisualState Name="Selected">
<VisualState.Setters>
<Setter Property="BackgroundColor"
Value="{AppThemeBinding Light={StaticResource Primary}, Dark={StaticResource PrimaryDark}}" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Label Text="{Binding Name}" />
</Grid>
</DataTemplate>
</CollectionView.ItemTemplate>Grouping
分组功能
- Create a group class inheriting from :
List<T>
csharp
public class AnimalGroup : List<Animal>
{
public string Name { get; }
public AnimalGroup(string name, List<Animal> animals) : base(animals)
{
Name = name;
}
}- Bind to and set
ObservableCollection<AnimalGroup>:IsGrouped="True"
xml
<CollectionView ItemsSource="{Binding AnimalGroups}"
IsGrouped="True">
<CollectionView.GroupHeaderTemplate>
<DataTemplate x:DataType="models:AnimalGroup">
<Label Text="{Binding Name}"
FontAttributes="Bold"
BackgroundColor="{StaticResource Gray100}"
Padding="8" />
</DataTemplate>
</CollectionView.GroupHeaderTemplate>
<CollectionView.ItemTemplate>
<DataTemplate x:DataType="models:Animal">
<Label Text="{Binding Name}" Padding="16,4" />
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>- 创建继承自的分组类:
List<T>
csharp
public class AnimalGroup : List<Animal>
{
public string Name { get; }
public AnimalGroup(string name, List<Animal> animals) : base(animals)
{
Name = name;
}
}- 绑定到并设置
ObservableCollection<AnimalGroup>:IsGrouped="True"
xml
<CollectionView ItemsSource="{Binding AnimalGroups}"
IsGrouped="True">
<CollectionView.GroupHeaderTemplate>
<DataTemplate x:DataType="models:AnimalGroup">
<Label Text="{Binding Name}"
FontAttributes="Bold"
BackgroundColor="{StaticResource Gray100}"
Padding="8" />
</DataTemplate>
</CollectionView.GroupHeaderTemplate>
<CollectionView.ItemTemplate>
<DataTemplate x:DataType="models:Animal">
<Label Text="{Binding Name}" Padding="16,4" />
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>Pull-to-Refresh
下拉刷新
Wrap in a . Set back to when done:
CollectionViewRefreshViewIsRefreshingfalsexml
<RefreshView IsRefreshing="{Binding IsRefreshing}"
Command="{Binding RefreshCommand}">
<CollectionView ItemsSource="{Binding Items}" />
</RefreshView>将包裹在中,完成刷新后将设回:
CollectionViewRefreshViewIsRefreshingfalsexml
<RefreshView IsRefreshing="{Binding IsRefreshing}"
Command="{Binding RefreshCommand}">
<CollectionView ItemsSource="{Binding Items}" />
</RefreshView>Incremental Loading (Infinite Scroll)
增量加载(无限滚动)
xml
<CollectionView ItemsSource="{Binding Items}"
RemainingItemsThreshold="5"
RemainingItemsThresholdReachedCommand="{Binding LoadMoreCommand}" />⚠️ Do NOT use with non-virtualizing layouts.andLinearItemsLayoutsupport virtualization. UsingGridItemsLayouton aBindableLayoutas an alternative toStackLayouthas no virtualization, which triggers infinite threshold-reached events.CollectionView
xml
<CollectionView ItemsSource="{Binding Items}"
RemainingItemsThreshold="5"
RemainingItemsThresholdReachedCommand="{Binding LoadMoreCommand}" />⚠️ 请勿与非虚拟化布局搭配使用。和LinearItemsLayout支持虚拟化。若使用GridItemsLayout上的StackLayout替代BindableLayout,则无虚拟化功能,会触发无限次的阈值到达事件。CollectionView
SwipeView — Binding from Inside DataTemplate
SwipeView — 从DataTemplate内部绑定
Commands inside a can't directly reach your ViewModel. Use :
DataTemplateRelativeSource AncestorTypexml
<CollectionView.ItemTemplate>
<DataTemplate x:DataType="models:Item">
<SwipeView>
<SwipeView.RightItems>
<SwipeItems>
<SwipeItem Text="Delete"
BackgroundColor="Red"
Command="{Binding BindingContext.DeleteCommand, Source={RelativeSource AncestorType={x:Type ContentPage}}}"
CommandParameter="{Binding}" />
</SwipeItems>
</SwipeView.RightItems>
<Grid Padding="8">
<Label Text="{Binding Name}" />
</Grid>
</SwipeView>
</DataTemplate>
</CollectionView.ItemTemplate>DataTemplateRelativeSource AncestorTypexml
<CollectionView.ItemTemplate>
<DataTemplate x:DataType="models:Item">
<SwipeView>
<SwipeView.RightItems>
<SwipeItems>
<SwipeItem Text="Delete"
BackgroundColor="Red"
Command="{Binding BindingContext.DeleteCommand, Source={RelativeSource AncestorType={x:Type ContentPage}}}"
CommandParameter="{Binding}" />
</SwipeItems>
</SwipeView.RightItems>
<Grid Padding="8">
<Label Text="{Binding Name}" />
</Grid>
</SwipeView>
</DataTemplate>
</CollectionView.ItemTemplate>EmptyView
空视图
Shown when is empty or null.
ItemsSourcexml
<CollectionView ItemsSource="{Binding SearchResults}"
EmptyView="No items found." />For a custom empty view, wrap in :
ContentViewxml
<CollectionView ItemsSource="{Binding SearchResults}">
<CollectionView.EmptyView>
<ContentView>
<VerticalStackLayout HorizontalOptions="Center" VerticalOptions="Center">
<Image Source="empty_state.png" WidthRequest="120" />
<Label Text="Nothing here yet" HorizontalTextAlignment="Center" />
</VerticalStackLayout>
</ContentView>
</CollectionView.EmptyView>
</CollectionView>当为空或null时展示:
ItemsSourcexml
<CollectionView ItemsSource="{Binding SearchResults}"
EmptyView="No items found." />如需自定义空视图,可包裹在中:
ContentViewxml
<CollectionView ItemsSource="{Binding SearchResults}">
<CollectionView.EmptyView>
<ContentView>
<VerticalStackLayout HorizontalOptions="Center" VerticalOptions="Center">
<Image Source="empty_state.png" WidthRequest="120" />
<Label Text="Nothing here yet" HorizontalTextAlignment="Center" />
</VerticalStackLayout>
</ContentView>
</CollectionView.EmptyView>
</CollectionView>Headers and Footers
页眉与页脚
xml
<CollectionView ItemsSource="{Binding Items}">
<CollectionView.Header>
<Label Text="Header" FontAttributes="Bold" Padding="8" />
</CollectionView.Header>
<CollectionView.Footer>
<Label Text="Footer" FontAttributes="Italic" Padding="8" />
</CollectionView.Footer>
</CollectionView>Use / when headers or footers are data-bound.
HeaderTemplateFooterTemplatexml
<CollectionView ItemsSource="{Binding Items}">
<CollectionView.Header>
<Label Text="Header" FontAttributes="Bold" Padding="8" />
</CollectionView.Header>
<CollectionView.Footer>
<Label Text="Footer" FontAttributes="Italic" Padding="8" />
</CollectionView.Footer>
</CollectionView>当页眉或页脚需要数据绑定时,使用/。
HeaderTemplateFooterTemplateScrolling
滚动功能
ScrollTo
滚动到指定位置
Programmatically scroll by index or item:
csharp
// Scroll to index
collectionView.ScrollTo(index: 10, position: ScrollToPosition.Center, animate: true);
// Scroll to item
collectionView.ScrollTo(item: myItem, position: ScrollToPosition.MakeVisible, animate: true);| ScrollToPosition | Behavior |
|---|---|
| Scrolls just enough to make the item visible |
| Scrolls item to the start of the viewport |
| Scrolls item to the center of the viewport |
| Scrolls item to the end of the viewport |
通过索引或项编程式滚动:
csharp
// 滚动到指定索引
collectionView.ScrollTo(index: 10, position: ScrollToPosition.Center, animate: true);
// 滚动到指定项
collectionView.ScrollTo(item: myItem, position: ScrollToPosition.MakeVisible, animate: true);| ScrollToPosition | 行为 |
|---|---|
| 滚动至刚好能显示该项的位置 |
| 滚动至该项位于视口起始处 |
| 滚动至该项位于视口中央 |
| 滚动至该项位于视口末尾 |
Snap Points
吸附点
xml
<CollectionView.ItemsLayout>
<LinearItemsLayout Orientation="Horizontal"
SnapPointsType="MandatorySingle"
SnapPointsAlignment="Center" />
</CollectionView.ItemsLayout>- :
SnapPointsType,None,MandatoryMandatorySingle - :
SnapPointsAlignment,Start,CenterEnd
xml
<CollectionView.ItemsLayout>
<LinearItemsLayout Orientation="Horizontal"
SnapPointsType="MandatorySingle"
SnapPointsAlignment="Center" />
</CollectionView.ItemsLayout>- :
SnapPointsType,None,MandatoryMandatorySingle - :
SnapPointsAlignment,Start,CenterEnd
Performance Tips
性能优化技巧
- Use for uniform item sizes — significantly faster than
MeasureFirstItem:MeasureAllItemsxml<LinearItemsLayout Orientation="Vertical" ItemSizingStrategy="MeasureFirstItem" /> - Always use , not
ObservableCollection<T>. Swapping aList<T>forces a full re-render.List - Update collections on the UI thread — .
MainThread.BeginInvokeOnMainThread(() => Items.Add(item))
- 使用:对于尺寸统一的项,此策略比
MeasureFirstItem快得多:MeasureAllItemsxml<LinearItemsLayout Orientation="Vertical" ItemSizingStrategy="MeasureFirstItem" /> - 始终使用,而非
ObservableCollection<T>。替换List<T>会触发完整的重新渲染。List - 在UI线程更新集合——使用。
MainThread.BeginInvokeOnMainThread(() => Items.Add(item))
Common Pitfalls
常见陷阱
| Issue | Fix |
|---|---|
| UI doesn't update when items change | Use |
| App crashes or blank items | Never use |
| Items disappear or layout breaks | Always update |
| Incremental loading fires endlessly | Don't use |
| EmptyView doesn't render correctly | Wrap custom empty views in |
| Poor scroll performance | Use |
| Selected state not visible | Add |
| Binding errors in SwipeView commands | Use |
| Using ListView instead of CollectionView | |
| 问题 | 解决方法 |
|---|---|
| 项变更时UI未更新 | 使用 |
| 应用崩溃或项显示空白 | 切勿使用 |
| 项消失或布局错乱 | 始终在UI线程更新 |
| 增量加载无限触发 | 不要使用 |
| 空视图渲染异常 | 将自定义空视图包裹在 |
| 滚动性能差 | 对于尺寸统一的项,使用 |
| 选中状态不可见 | 为项模板根元素添加 |
| SwipeView命令绑定出错 | 使用 |
| 仍在使用ListView而非CollectionView | |