如何在.NET MAUI的MVVM架构中用List绑定ListView或CollectionView展示数据
.NET MAUI MVVM下绑定ListView/CollectionView并实现动态更新
核心前提:用ObservableCollection替代List
普通List<T>没有实现集合变更通知接口,底层数据增删改时UI不会自动刷新。必须换成ObservableCollection<T>——它实现了INotifyCollectionChanged接口,能在集合元素变化时自动触发UI更新。
同时你的ViewModel需要实现INotifyPropertyChanged接口,确保属性值变更时能通知绑定的UI控件。
分步实现
1. 定义数据实体类
先创建要展示的数据模型,比如一个待办项:
public class TodoItem { public string Title { get; set; } public bool IsCompleted { get; set; } }
如果需要单个实体属性变更时UI同步刷新,TodoItem也需要实现INotifyPropertyChanged接口
2. 实现ViewModel
ViewModel要继承实现INotifyPropertyChanged的基类,或直接使用CommunityToolkit.Mvvm简化开发:
方式一:手动实现INotifyPropertyChanged
using System.Collections.ObjectModel; using System.ComponentModel; using System.Runtime.CompilerServices; public class BaseViewModel : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; protected void OnPropertyChanged([CallerMemberName] string propertyName = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } } public class TodoViewModel : BaseViewModel { private ObservableCollection<TodoItem> _todoItems; public ObservableCollection<TodoItem> TodoItems { get => _todoItems; set { _todoItems = value; OnPropertyChanged(); } } // 示例:添加数据方法 public void AddTodoItem() { TodoItems.Add(new TodoItem { Title = $"新待办项 {TodoItems.Count + 1}" }); } // 示例:删除数据方法 public void RemoveLastTodoItem() { if (TodoItems.Count > 0) TodoItems.RemoveAt(TodoItems.Count - 1); } public TodoViewModel() { // 初始化测试数据 TodoItems = new ObservableCollection<TodoItem> { new TodoItem { Title = "完成MAUI绑定教程", IsCompleted = false }, new TodoItem { Title = "测试动态更新", IsCompleted = true } }; } }
方式二:用CommunityToolkit.Mvvm(推荐)
先安装CommunityToolkit.Mvvm NuGet包,ViewModel可以更简洁:
using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; using System.Collections.ObjectModel; public partial class TodoViewModel : ObservableObject { [ObservableProperty] private ObservableCollection<TodoItem> _todoItems; [RelayCommand] public void AddTodoItem() { TodoItems.Add(new TodoItem { Title = $"新待办项 {TodoItems.Count + 1}" }); } [RelayCommand] public void RemoveLastTodoItem() { if (TodoItems.Count > 0) TodoItems.RemoveAt(TodoItems.Count - 1); } public TodoViewModel() { TodoItems = new ObservableCollection<TodoItem> { new TodoItem { Title = "完成MAUI绑定教程", IsCompleted = false }, new TodoItem { Title = "测试动态更新", IsCompleted = true } }; } }
3. XAML页面绑定CollectionView(推荐)
CollectionView是MAUI官方推荐的列表控件,比ListView更灵活。在XAML中设置ItemsSource绑定到ViewModel的集合属性,通过ItemTemplate定义项布局:
<?xml version="1.0" encoding="utf-8" ?> <ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:vm="clr-namespace:YourAppNamespace.ViewModels" x:Class="YourAppNamespace.Views.TodoPage" Title="待办列表"> <!-- 设置页面BindingContext --> <ContentPage.BindingContext> <vm:TodoViewModel /> </ContentPage.BindingContext> <VerticalStackLayout Padding="10" Spacing="10"> <!-- 测试按钮:触发数据变更 --> <Button Text="添加待办" Command="{Binding AddTodoItemCommand}" /> <Button Text="删除最后一项" Command="{Binding RemoveLastTodoItemCommand}" /> <!-- CollectionView绑定数据源 --> <CollectionView ItemsSource="{Binding TodoItems}" Margin="0,10,0,0"> <CollectionView.ItemTemplate> <DataTemplate> <HorizontalStackLayout Spacing="10" Padding="5"> <CheckBox IsChecked="{Binding IsCompleted}" /> <Label Text="{Binding Title}" FontSize="16" HorizontalOptions="FillAndExpand" /> </HorizontalStackLayout> </DataTemplate> </CollectionView.ItemTemplate> </CollectionView> </VerticalStackLayout> </ContentPage>
4. (可选)绑定ListView
如果需要使用ListView,写法类似:
<ListView ItemsSource="{Binding TodoItems}"> <ListView.ItemTemplate> <DataTemplate> <ViewCell> <HorizontalStackLayout Spacing="10" Padding="5"> <CheckBox IsChecked="{Binding IsCompleted}" /> <Label Text="{Binding Title}" FontSize="16" /> </HorizontalStackLayout> </ViewCell> </DataTemplate> </ListView.ItemTemplate> </ListView>
关键注意事项
- 必须使用
ObservableCollection<T>而非List<T>,否则增删元素时UI不会刷新。 - ViewModel必须实现
INotifyPropertyChanged,确保集合属性本身重新赋值时能通知UI。 - 绑定路径要准确:
ItemsSource="{Binding TodoItems}"中的TodoItems必须是ViewModel的公共属性。 - 若实体属性变更需要同步UI,实体类也需实现
INotifyPropertyChanged。
内容的提问来源于stack exchange,提问作者Haseeb Ahmad
相关产品推荐
相关产品推荐

