如何在筛选后的WPF DataGrid中获取正确的行索引
解决WPF DataGrid筛选后获取正确索引并刷新恢复选中的问题
这个问题的核心其实是混淆了DataGrid的视图索引和原始数据源的实体标识——当DataGrid应用筛选后,Items集合是经过筛选的视图(比如ICollectionView),此时的SelectedIndex是视图内的位置,而非原始数据源中的索引。直接保存这个索引,刷新数据源后自然对应不上正确的实体。
正确的思路:保存实体的唯一标识,而非索引
不管筛选与否,我们应该跟踪选中的实体本身或者它的唯一标识(比如ID),而不是依赖视图的索引。步骤如下:
刷新前记录选中实体的唯一标识
在打开编辑对话框前,先获取当前选中的实体(不管是否筛选,SelectedItem都是实际的实体对象),然后记录它的唯一ID:// 假设你的实体类是MyDataItem,有一个唯一标识属性Id MyDataItem selectedItem = grid.SelectedItem as MyDataItem; int? selectedId = selectedItem?.Id;刷新数据源并重新应用筛选
从数据库重新读取数据后,重置DataGrid的数据源,同时确保筛选条件被重新应用(如果之前有筛选的话):// 假设你的ViewModel里的数据源是ObservableCollection<MyDataItem> DataItems vm.RefreshList(); // 这个方法负责从数据库重新加载数据到DataItems // 如果之前有筛选条件,重新应用到ICollectionView ICollectionView view = CollectionViewSource.GetDefaultView(vm.DataItems); view.Filter = yourExistingFilterLogic; // 比如之前的筛选委托根据唯一标识恢复选中状态
数据源刷新并重新筛选后,找到对应ID的实体,设置为SelectedItem,同时滚动到该行:if (selectedId.HasValue) { MyDataItem itemToSelect = vm.DataItems.FirstOrDefault(item => item.Id == selectedId.Value); if (itemToSelect != null) { grid.SelectedItem = itemToSelect; // 确保该行滚动到可视区域 grid.ScrollIntoView(itemToSelect); } }
为什么之前的方法失效?
- 筛选后的
SelectedIndex/IndexOf(CurrentItem)返回的是筛选视图内的索引,不是原始数据源的索引,刷新后视图重置,这个索引自然指向错误的实体。 - 使用
ItemContainerGenerator的方式依赖UI容器,刷新数据源后UI容器会被重建,原来的row对象会失效,所以无法通过它获取正确的索引。
额外优化:绑定SelectedItem到ViewModel
更好的做法是在ViewModel中添加一个SelectedDataItem属性,通过数据绑定关联到DataGrid的SelectedItem:
<DataGrid x:Name="grid" ItemsSource="{Binding DataItems}" SelectedItem="{Binding SelectedDataItem}" ... />
这样你不需要直接操作DataGrid控件,直接在ViewModel中记录SelectedDataItem.Id,刷新后再找到对应实体赋值给SelectedDataItem即可,更符合MVVM模式。
内容的提问来源于stack exchange,提问作者Patrick Pirzer
相关产品推荐
相关产品推荐

