WPF DataGrid新增行时SelectedItems未同步UI选中状态的问题
WPF DataGrid新增行后SelectedItems持续增长的问题分析与解决
问题原因
当你的DataGrid设置了CanUserAddRows="True"时,WPF会自动在Items集合末尾添加一个**CollectionView.NewItemPlaceholder**对象作为新增行的占位符。这个占位符虽然在UI上显示为可编辑的空行,但它并不是你业务模型中的实际数据对象:
- 当你开始编辑这个占位符行时,DataGrid会将这个占位符加入
SelectedItems集合,触发SelectionChanged事件; - 当编辑完成(比如行失去焦点),DataGrid会用你业务模型的实例替换这个占位符,同时生成新的占位符行;
- 但此时,原来的占位符对象并没有被自动从
SelectedItems中移除——因为它已经不在DataGrid的Items集合里了,UI不会渲染它,但SelectedItems依然持有这个无效引用,导致集合大小持续增长,而UI上只能看到当前有效的选中行。
另外,你设置了SelectionMode="Single",但这个模式只对有效数据项生效,无法自动过滤掉NewItemPlaceholder这种特殊对象,所以才会出现"UI只有单行选中,但SelectedItems持续变大"的矛盾现象。
解决方法
针对这个问题,有两种直接有效的解决方式:
1. 在SelectionChanged事件中过滤无效项
在你已经绑定的dataGrid_SelectionChanged事件中,手动移除SelectedItems中的NewItemPlaceholder对象,确保集合中只保留有效的业务数据项:
using System.Windows.Data; // 需要引入这个命名空间才能访问CollectionView private void dataGrid_SelectionChanged(object sender, SelectionChangedEventArgs e) { // 筛选出所有NewItemPlaceholder类型的无效项 var invalidPlaceholderItems = dataGrid.SelectedItems.Cast<object>() .Where(item => CollectionView.NewItemPlaceholder.Equals(item)) .ToList(); // 从SelectedItems中移除这些无效项 foreach (var invalidItem in invalidPlaceholderItems) { dataGrid.SelectedItems.Remove(invalidItem); } // 这里可以更新你的TextBox显示,验证选中数量是否正确 selectionBox.Text = $"当前选中行数:{dataGrid.SelectedItems.Count}"; }
2. 确保ItemsSource使用ObservableCollection
你的GeneralTasks属性必须是ObservableCollection<YourTaskModel>类型(而不是普通的List<T>),因为ObservableCollection会自动通知UI集合的变化,DataGrid才能正确跟踪项的添加/替换操作,减少无效引用残留的概率:
// 在你的ViewModel或窗口类中定义 public ObservableCollection<YourTaskModel> GeneralTasks { get; set; } // 初始化时赋值 public SampleWindow() { InitializeComponent(); GeneralTasks = new ObservableCollection<YourTaskModel>(); DataContext = this; // 如果是直接绑定到窗口的话 }
额外注意事项
- 避免在
SelectionChanged事件中做复杂的业务逻辑,防止因为多次触发(新增行过程中会触发多次)导致的性能问题; - 如果你的DataGrid设置了
SelectionUnit="Cell"或CellOrRowHeader,也可能出现类似的选中残留问题,但你的代码中设置的是FullRow,所以上面的方法完全适用。
内容的提问来源于stack exchange,提问作者gurbi
相关产品推荐
相关产品推荐

