You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NET MAUI:派生ObservableCollection不触发UI渲染及实现方式咨询

.NET MAUI派生集合不触发UI更新的问题解决

问题原因

你当前的实现有两个核心问题导致UI不更新:

  1. 仅监听集合本身的变化,未监听元素属性变化:[NotifyPropertyChangedFor(nameof(CompletedTodos))]只会在Todos集合被重新赋值、添加/删除元素时触发通知,但当集合内单个TODO的IsCompleted属性变化时,Todos集合本身不会引发PropertyChanged事件,因此CompletedTodos的更新通知不会被发送,UI也就不会重新获取派生集合。
  2. 每次访问都新建集合实例:CompletedTodos每次调用都会创建新的ObservableCollection,UI绑定的是第一次获取的集合实例,即便后续新集合有数据,UI也不会自动切换到新实例。

正确实现方式

推荐使用ICollectionView(.NET内置的集合视图),它基于原集合做过滤,无需新建集合,还能自动监听元素属性变化:

ViewModel代码

using System.ComponentModel;
using System.Windows.Data;
using CommunityToolkit.Mvvm.ComponentModel;

public partial class YourViewModel : ObservableObject
{
    [ObservableProperty]
    ObservableCollection<TODO> todos = new();

    public ICollectionView CompletedTodosView { get; }

    public YourViewModel()
    {
        // 创建基于Todos的集合视图
        CompletedTodosView = CollectionViewSource.GetDefaultView(Todos);
        // 设置过滤规则
        CompletedTodosView.Filter = item => ((TODO)item).IsCompleted;
    }
}

// 确保TODO类实现INotifyPropertyChanged
public class TODO : INotifyPropertyChanged
{
    private bool _isCompleted;
    public bool IsCompleted
    {
        get => _isCompleted;
        set
        {
            _isCompleted = value;
            OnPropertyChanged(nameof(IsCompleted));
        }
    }

    public event PropertyChangedEventHandler? PropertyChanged;
    private void OnPropertyChanged(string propertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

    // 其他属性...
}

XAML代码

<CollectionView ItemsSource="{Binding CompletedTodosView}"/>

替代方案(维护独立ObservableCollection)

如果必须使用独立的ObservableCollection,需要手动监听集合和元素的变化:

public partial class YourViewModel : ObservableObject
{
    [ObservableProperty]
    ObservableCollection<TODO> todos = new();

    private readonly ObservableCollection<TODO> _completedTodos = new();
    public ObservableCollection<TODO> CompletedTodos => _completedTodos;

    public YourViewModel()
    {
        Todos.CollectionChanged += Todos_CollectionChanged;
        UpdateCompletedTodos();
    }

    private void Todos_CollectionChanged(object? sender, NotifyCollectionChangedEventArgs e)
    {
        // 订阅/取消订阅元素的PropertyChanged事件
        if (e.NewItems != null)
        {
            foreach (TODO item in e.NewItems)
                item.PropertyChanged += Todo_PropertyChanged;
        }
        if (e.OldItems != null)
        {
            foreach (TODO item in e.OldItems)
                item.PropertyChanged -= Todo_PropertyChanged;
        }
        UpdateCompletedTodos();
    }

    private void Todo_PropertyChanged(object? sender, PropertyChangedEventArgs e)
    {
        if (e.PropertyName == nameof(TODO.IsCompleted))
            UpdateCompletedTodos();
    }

    private void UpdateCompletedTodos()
    {
        _completedTodos.Clear();
        foreach (var todo in Todos.Where(t => t.IsCompleted))
            _completedTodos.Add(todo);
    }
}

关于实现方式的选择

当前的实现方式不正确,不需要使用Behavior/Converter,ICollectionView是最简洁高效的方案,它原生支持集合过滤、排序和分组,且能自动同步UI。

内容的提问来源于stack exchange,提问作者rohanharikr

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 10:23:37