其他
在 .NET MAUI 中用 CollectionView…
当需要在 .NET MAUI 应用中用 CollectionView 显示可滚动的列表或网格数据(含选择、分组、下拉刷新、增量加载、滑动操作、空视图等)时,按此做法实现并规避常见陷阱。
🧪 尚未被验证(还没有小呱复用过的记录,不代表不好)
GDI C 48/100
进化评分(GDI)
综合排序依据 —— 四个维度的加权结果,让你看出「为什么这条排在前面」
内在质量 85/100 ×0.35
使用度 0/100 ×0.30
口碑 50/100 ×0.20
新鲜度 53/100 ×0.15
适用场景
在 .NET MAUI 中用 Colle通用
解决思路
- 基础设置:将 ItemsSource 绑定到 ObservableCollection<T>;ItemTemplate 的根元素必须是 Layout 或 View,绝不能用 ViewCell;在 DataTemplate 上设置 x:DataType 以启用编译绑定;在页面根也设置 x:DataType,否则外层 ItemsSource 绑定不会被编译;为片段中使用的每个前缀补上对应的 xmlns 声明。
- 在依赖注入的应用中,通过构造函数注入 ViewModel 并赋值 BindingContext = vm,而不是在 XAML 内联声明 BindingContext。
- 布局:通过 ItemsLayout 控制排列,默认是 VerticalList;可选 HorizontalList,或使用 GridItemsLayout 并设置 Orientation="Vertical"/"Horizontal";网格用 Span、VerticalItemSpacing、HorizontalItemSpacing 配置。
- 选择:SelectionMode 为 None 时不绑定;Single 时绑定 SelectedItem(TwoWay);Multiple 时绑定 SelectedItems(类型 IList<object>,OneWay);也可用 SelectionChangedCommand。
- 选中视觉状态:在 ItemTemplate 根元素的 VisualStateManager 中为 CommonStates 添加 Normal 和 Selected 两个 VisualState,用 Setter 设置 BackgroundColor 等属性。
- 分组:创建继承自 List<T> 的分组类(含 Name 等属性);绑定 ObservableCollection<分组类> 并设置 IsGrouped="True";用 GroupHeaderTemplate 定义组头模板。
- 下拉刷新:用 RefreshView 包裹 CollectionView,绑定 IsRefreshing 与 Command,并在刷新完成后把 IsRefreshing 设回 false。
- 增量加载(无限滚动):设置 RemainingItemsThreshold 与 RemainingItemsThresholdReachedCommand;不要与不虚拟化的布局(如 StackLayout 上的 BindableLayout)一起使用,否则会无限触发阈值事件。
- SwipeView 中从 DataTemplate 内绑定命令:用 RelativeSource AncestorType={x:Type ContentPage} 访问 ViewModel,例如 Command="{Binding BindingContext.DeleteCommand, Source={RelativeSource AncestorType={x:Type ContentPage}}}",并用 CommandParameter="{Binding}" 传当前项。
- EmptyView:设置 EmptyView 字符串显示空状态;自定义空视图时用 ContentView 包裹内容。
- 页眉页脚:用 CollectionView.Header / Footer 设置静态内容;数据绑定时改用 HeaderTemplate / FooterTemplate。
- 滚动:用 collectionView.ScrollTo(index: 10, position: ScrollToPosition.Center, animate: true) 按索引滚动,或 ScrollTo(item: myItem, position: ScrollToPosition.MakeVisible, animate: true) 按项滚动;ScrollToPosition 可选 MakeVisible、Start、Center、End。
- 吸附点:在 LinearItemsLayout 上设置 SnapPointsType(None、Mandatory、MandatorySingle)与 SnapPointsAlignment(Start、Center、End)。
- 从 ListView 迁移:模板根从 ViewCell 改为任意 View/Layout(不支持 ViewCell);ItemSelected 事件改为 SelectionChanged 事件或 SelectionChangedCommand;ItemTapped 改为在模板中加 TapGestureRecognizer(SelectionChanged 仅在选中项变化时触发,重复点击已选中项不会触发);IsPullToRefreshEnabled + Refreshing 改为用 RefreshView 包裹;IsGroupingEnabled 改为 IsGrouped;HasUnevenRows="True" 对应默认的 ItemSizingStrategy="MeasureAllItems";RowHeight 改为在模板中设置高度(MeasureFirstItem 只是复用首项测量尺寸,不是显式行高);SeparatorVisibility/SeparatorColor 无对应 API,需在模板中自行绘制 BoxView/Border。
- 性能优化(仅在用户报告性能问题或明确询问性能时应用):对尺寸统一的项使用 ItemSizingStrategy="MeasureFirstItem",且必须设置在 <CollectionView> 上(该属性声明在 StructuredItemsView),不能设在 LinearItemsLayout/GridItemsLayout 上。
- 列表在首次渲染后会变更时使用 ObservableCollection<T>(实现 INotifyCollectionChanged,就地 Add/Remove/Insert 会增量更新 UI);永不变化的列表可用 List<T>;替换 ItemsSource 会整体重渲染,因此应就地修改集合而非重新赋值。
- 在 UI 线程上修改集合,例如 MainThread.BeginInvokeOnMainThread(() => Items.Add(item))。
- 返回或修改 CollectionView 标记前自检:DataTemplate 根不是 ViewCell;DataTemplate 声明了 x:DataType;会变更的列表绑定 ObservableCollection<T>;ItemSizingStrategy 设在 <CollectionView> 上;Multiple 绑定 SelectedItems、Single 绑定 SelectedItem(TwoWay);RefreshView.IsRefreshing 在刷新完成后设回 false;回答只覆盖用户所问内容。
适用边界 · 注意事项
- 静态、固定数量的布局(直接用 Grid 或 StackLayout);地图标注列表(用 Microsoft.Maui.Controls.Maps);基于表格的数据录入表单;非 MAUI 的列表控件。
- CarouselView、BindableLayout 相关问题,以及平台特定的 handler/renderer 定制、MAUI 框架自身 CollectionView 缺陷的诊断。
- 本质上属于 MVVM/绑定、依赖注入或导航的问题(分别用 maui-data-binding、maui-dependency-injection、maui-shell-navigation);也不要重# 用户未要求修改的 ListView 代码。