在.NET MAUI MVVM的ViewModel中实现列表过滤的问题
.NET MAUI MVVM 实现产品列表过滤的正确方式
核心解决思路:将原始产品数据源与UI绑定的过滤后数据源完全分离,避免引用同一集合导致的修改冲突与多次过滤失效,同时规范异步数据加载与集合变更通知逻辑。
1. 修正ViewModel的字段与属性定义
- 保留只读的原始数据集合,仅在初始化时赋值,后续所有过滤操作均基于该集合执行
- 使用
ObservableCollection<Product>作为UI绑定属性,利用其自带的集合变更通知能力自动更新UI - 替换
.Result的异步请求方式,改用async/await避免死锁
// 原始完整产品数据:仅初始化时赋值,后续不修改 private List<Product> _originalProducts; // 用于UI绑定的过滤后数据集合 private ObservableCollection<Product> _filteredProducts; public ObservableCollection<Product> FilteredProducts { get => _filteredProducts; set { if (_filteredProducts != value) { _filteredProducts = value; OnPropertyChanged(); } } } // 假设ViewModel已实现INotifyPropertyChanged接口 public YourViewModel(HttpClient httpClient) { // 异步加载服务器数据 _ = LoadProductsAsync(httpClient); } private async Task LoadProductsAsync(HttpClient httpClient) { _originalProducts = await httpClient.GetFromJsonAsync<List<Product>>("http://10.0.2.2:5192/api/Product"); // 初始化时显示全部产品 FilteredProducts = new ObservableCollection<Product>(_originalProducts); }
2. 实现正确的过滤方法
过滤操作直接基于原始数据生成新结果,避免在枚举集合时修改原集合:
方式一:直接替换ObservableCollection(简单高效)
private void OnFilterTextChanged(string filterText) { if (string.IsNullOrWhiteSpace(filterText)) { // 过滤文本为空时恢复显示全部原始数据 FilteredProducts = new ObservableCollection<Product>(_originalProducts); return; } // 基于原始数据执行过滤,生成新集合 var filteredItems = _originalProducts.Where(p => p.Title.Contains(filterText, StringComparison.OrdinalIgnoreCase)) .ToList(); FilteredProducts = new ObservableCollection<Product>(filteredItems); }
方式二:清空现有集合并添加结果(适合需保留集合引用的场景)
如果需要维持FilteredProducts的引用(例如绑定了选择项),可使用该方式:
private void OnFilterTextChanged(string filterText) { FilteredProducts.Clear(); IEnumerable<Product> targetItems = string.IsNullOrWhiteSpace(filterText) ? _originalProducts : _originalProducts.Where(p => p.Title.Contains(filterText, StringComparison.OrdinalIgnoreCase)); foreach (var product in targetItems) { FilteredProducts.Add(product); } }
3. 解决原代码的核心问题
- 枚举修改集合异常:原代码中
Products与Prodyct引用同一集合,枚举时修改集合必然触发异常。分离数据源后,枚举的是只读原始集合,修改的是独立的过滤集合,无冲突。 - 多次过滤失效:原代码修改了原始集合,导致后续过滤无完整数据可用。现在所有过滤均基于未改动的
_originalProducts,每次过滤都从完整数据重新计算。 - UI不更新:
ObservableCollection会自动触发集合变更通知,无需手动调用OnPropertyChanged即可更新UI。
4. XAML绑定调整
将UI控件的数据源绑定改为FilteredProducts,示例如下:
<!-- 产品列表绑定 --> <CollectionView ItemsSource="{Binding FilteredProducts}"> <!-- 产品模板内容 --> </CollectionView> <!-- 过滤输入框绑定(推荐结合ViewModel的FilterText属性) --> <Entry Text="{Binding FilterText}" />
若需自动触发过滤,可在ViewModel中添加FilterText属性并在setter中调用过滤方法:
private string _filterText; public string FilterText { get => _filterText; set { if (_filterText != value) { _filterText = value; OnPropertyChanged(); OnFilterTextChanged(_filterText); } } }
内容的提问来源于stack exchange,提问作者vhhs
相关产品推荐
相关产品推荐

