.NET Maui编辑ObservableCollection项后ObservableView未更新问题
问题描述
使用MVVM Community Toolkit时,添加或删除项时ObservableCollection能正常更新视图,但编辑项时视图无法同步更新。调试确认ObservableCollection中的项已经被正确修改,试过绑定IsRefreshing手动刷新、清空再重新填充集合,都没用。
相关代码
模型类
public partial class ToDoTask : ObservableObject { string taskName; string? description = null; string? notes = null; DateTime createdDate; DateTime? dueDate = null; bool hasDueDate; bool isOverdue; bool isComplete; string? taskLocation = null; Employee? assignor = null; Project? project = null; ObservableCollection<ToDoTask> subtasks = new ObservableCollection<ToDoTask>(); ObservableCollection<Employee> assignees = new ObservableCollection<Employee>(); public string TaskName { get => taskName; set => SetProperty(ref taskName, value); } }
主视图模型
public partial class MainViewModel : ObservableObject { public MainViewModel() { Items = new ObservableCollection<ToDoTask>(); } [ObservableProperty] ObservableCollection<ToDoTask> items; [ObservableProperty] bool isRefreshing; [ObservableProperty] string text; [ObservableProperty] DateTime? dueDate; [ObservableProperty] DateTime? createdDate; [RelayCommand] void Add() { NewTask(); } [RelayCommand] void Delete(ToDoTask s) { if(Items.Contains(s)) { Items.Remove(s); } } [RelayCommand] public void PageAppearing() { IsRefreshing = true; List<ToDoTask> temp = new(); foreach(ToDoTask t in Items) { temp.Add(t); } Items.Clear(); foreach (ToDoTask t in temp) { Items.Add(t); } IsRefreshing = false; } [RelayCommand] async Task Tap(ToDoTask s) { await Shell.Current.GoToAsync($"{nameof(TaskPage)}", new Dictionary<string, object> { { "Item", s }, { "Items", Items} }); } async Task NewTask() { ToDoTask temp = new ToDoTask(); await Shell.Current.GoToAsync($"{nameof(TaskPage)}", new Dictionary<string, object> { { "Items", Items }, { "Item", temp } }); } }
XAML代码
<RefreshView Command="{Binding Source={RelativeSource AncestorType={x:Type viewmodel:MainViewModel}}, Path=RefreshCommand}" CommandParameter="{Binding .}" IsRefreshing="{Binding Source={RelativeSource AncestorType={x:Type viewmodel:MainViewModel}}, Path=IsRefreshing}" Grid.Row="2" Grid.ColumnSpan="2"> <CollectionView ItemsSource="{Binding Items}" SelectionMode="None" CanReorderItems="True"> <CollectionView.ItemTemplate> <DataTemplate x:DataType="{x:Type x:String}"> <SwipeView> <SwipeView.RightItems> <SwipeItems> <SwipeItem Text="Delete" BackgroundColor="Red" Command="{Binding Source={RelativeSource AncestorType={x:Type viewmodel:MainViewModel}}, Path=DeleteCommand}" CommandParameter="{Binding .}"/> </SwipeItems> </SwipeView.RightItems> <SwipeView.LeftItems> <SwipeItems> <SwipeItem Text="Edit" BackgroundColor="LightGreen" Command="{Binding Source={RelativeSource AncestorType={x:Type viewmodel:MainViewModel}}, Path=EditTaskCommand}" CommandParameter="{Binding .}"/> </SwipeItems> </SwipeView.LeftItems> <Grid Padding="0,5"> <Frame> <Frame.GestureRecognizers> <TapGestureRecognizer NumberOfTapsRequired="2" Command="{Binding Source={RelativeSource AncestorType={x:Type viewmodel:MainViewModel}}, Path=TapCommand}" CommandParameter="{Binding .}"/> </Frame.GestureRecognizers> <Label Text="{Binding .}" FontSize="18"/> </Frame> </Grid> </SwipeView> </DataTemplate> </CollectionView.ItemTemplate> </CollectionView> </RefreshView>
尝试过的解决方案
添加了MAUI Community Toolkit并做了如下配置:
XAML配置
xmlns:behaviors="http://schemas.microsoft.com/dotnet/2022/maui/toolkit" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="TaskMaster_DEV.MainPage" xmlns:viewmodel="clr-namespace:TaskMaster_DEV.ViewModel" x:DataType="viewmodel:MainViewModel"> <ContentPage.Behaviors> <behaviors:EventToCommandBehavior EventName="Appearing" Command="{Binding PageAppearingCommand}"> </behaviors:EventToCommandBehavior> </ContentPage.Behaviors>
任务视图模型
[QueryProperty("Item", "Item")] [QueryProperty("Items", "Items")] public partial class TaskViewModel : ObservableObject { [ObservableProperty] ToDoTask item; [ObservableProperty] ObservableCollection<ToDoTask> items; [RelayCommand] public void Save() { // 尝试让视图更新,失败了 if (!Items.Contains(Item)) { Items.Add(Item); } Shell.Current.GoToAsync(".."); } }
这些方法都没解决问题,还搞坏了原本正常的功能。作为新手,想知道有没有人成功实现编辑项后更新CollectionView的方案?
解决方案
问题核心是绑定配置错误,导致视图无法感知到项的属性变化,以下是修复步骤:
- 修正DataTemplate的类型绑定
你的CollectionView绑定的是ToDoTask集合,但DataTemplate错误地指定了x:DataType="{x:Type x:String}",这会让绑定系统无法识别ToDoTask的属性。
- 先在XAML根节点添加
ToDoTask所在的命名空间,比如:xmlns:local="clr-namespace:TaskMaster_DEV" <!-- 替换成你的项目命名空间 --> - 把DataTemplate的
x:DataType改成{x:Type local:ToDoTask},同时把Label的绑定改成具体属性(比如TaskName):<CollectionView.ItemTemplate> <DataTemplate x:DataType="{x:Type local:ToDoTask}"> <SwipeView> <!-- 其他SwipeItem代码不变 --> <Label Text="{Binding TaskName}" FontSize="18"/> <!-- 其他代码不变 --> </SwipeView> </DataTemplate> </CollectionView.ItemTemplate>
移除无效的手动刷新逻辑
ToDoTask已经继承ObservableObject,且属性通过SetProperty实现了INotifyPropertyChanged通知,只要绑定正确,属性更新时视图会自动刷新。删掉PageAppearing方法里清空再重新添加集合的代码,这个操作完全多余,还可能引发异常。简化Save方法
编辑现有任务时,你传递的是集合里的原实例,属性修改后绑定系统会自动同步,不需要判断是否添加到集合:
[RelayCommand] public void Save() { Shell.Current.GoToAsync(".."); }
完成以上修改后,编辑ToDoTask的任意属性(比如TaskName),CollectionView都会自动更新对应的视图内容。
内容的提问来源于stack exchange,提问作者AFranklin
相关产品推荐
相关产品推荐

