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

WINUI+MVVM中每次实例化ObservableCollection做过滤是否合规?

关于CRUD ViewModel中过滤操作的实践建议

直接new ObservableCollection的优缺点

优点

  • 实现简单:不用处理集合内项的增删逻辑,直接替换整个集合就能完成过滤,快速实现功能。

缺点

  1. 性能与GC压力:频繁创建新集合会增加垃圾回收负担,数据量较大时,销毁旧集合、创建新集合的开销会逐渐显现,甚至导致UI短暂卡顿。
  2. 丢失UI状态:替换集合后,Grid的选中项、滚动位置等状态会被重置,用户体验较差。
  3. 编辑冲突风险:如果用户正在编辑某条记录,替换集合会直接中断编辑流程,未保存的修改可能丢失。

这种做法不属于良好实践,仅适合数据量极小、对体验要求不高的场景。

推荐的替代方案

方案1:复用现有ObservableCollection,手动更新内容

保留同一个集合实例,通过清空、添加过滤后的项实现过滤,减少对象创建开销。数据量较大时,建议用批量操作(比如实现AddRange扩展方法)减少PropertyChanged事件触发次数,避免UI频繁刷新。

修改后的DoSearch示例:

private async Task DoSearch(string textToSearch)
{
    var filteredPeople = await _context.People.Where(x => x.Cognome.Contains(textToSearch)).ToListAsync();
    
    // 清空现有集合
    people.Clear();
    // 批量添加过滤后的项
    foreach (var person in filteredPeople)
    {
        people.Add(person);
    }
    // ObservableCollection的增删会自动通知UI,无需手动触发OnPropertyChanged
}

方案2:使用ICollectionView实现UI层面过滤(推荐)

利用WPF/UWP提供的ICollectionView(或CollectionViewSource),在原集合基础上做过滤,无需修改集合本身。这种方式既能保留原集合的所有数据,又能实现动态过滤,同时保留UI状态。

步骤:

  1. 在ViewModel中添加ICollectionView属性:
private ICollectionView _peopleView;
public ICollectionView PeopleView
{
    get => _peopleView;
    set => SetProperty(ref _peopleView, value);
}
  1. 在构造函数中初始化View:
people = new ObservableCollection<Person>(_context.People);
PeopleView = CollectionViewSource.GetDefaultView(people);
// 初始化过滤规则
PeopleView.Filter = obj => 
{
    if (string.IsNullOrEmpty(_searchText)) return true;
    var person = obj as Person;
    return person?.Cognome.Contains(_searchText) ?? false;
};
  1. 添加搜索文本属性,修改时刷新过滤:
private string _searchText = string.Empty;
public string SearchText
{
    get => _searchText;
    set
    {
        if (SetProperty(ref _searchText, value))
        {
            PeopleView.Refresh();
        }
    }
}
  1. 修改DoSearch(或直接绑定SearchText到输入框,无需命令):
private async Task DoSearch(string textToSearch)
{
    SearchText = textToSearch;
    // 无需修改集合,View会自动过滤
}

针对“Grid中创建新记录并过滤后编辑保存”的适配

如果用ICollectionView方案:

  • 新增记录时直接添加到people集合,只要符合当前过滤条件,会自动显示在Grid中;编辑后调用SaveCommand即可保存到数据库,完全不影响过滤状态。
  • 若新增记录不符合当前过滤条件,会保留在原集合中但不显示,保存后依然存在于数据库,后续搜索时会正常展示。

如果用复用集合的方案:

  • 新增记录时,先添加到_context.People,再判断是否符合当前过滤条件,符合则添加到people集合,不符合则仅保留在上下文,保存后下次搜索会显示。

额外代码优化建议

  • 在DoSearch中,应通过People属性的SetProperty赋值,而非直接修改字段后手动触发OnPropertyChanged,符合MVVM规范:
// 原写法
people = new ObservableCollection<Person>(...);
OnPropertyChanged(nameof(People));

// 优化后
People = new ObservableCollection<Person>(await _context.People.Where(...).ToListAsync());

内容的提问来源于stack exchange,提问作者Luca C.

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 01:07:39