Posts

WPF DataGrid 选择机制:SelectedCells 与 SelectionUnit

结论

SelectedCells 是 DataGrid 内部唯一的单元格级选择存储(DataGrid.cs:4094 返回内部字段 _selectedCells),而 SelectionUnit 决定的是”允许以什么粒度产生选择”以及”选择是否与行(SelectedItems)联动”。一句话概括:SelectionUnit 是规则,SelectedCells 是状态。

SelectedCells 的本质

SelectionUnit 三种取值的行为对照

行为FullRow(默认)CellCellOrRowHeader
点击单元格选中整行 MakeFullRowSelection选中该单元格 MakeCellSelection选中该单元格
点击行头选中整行无效果选中整行+填充该行全部 Cells
Ctrl+A / SelectAllSelectAll() 选行SelectAllCells() 选全部单元格SelectAll() 选行
代码直改 SelectedCells❌ 抛 InvalidOperationException✅ 允许✅ 允许(联动行)
SelectedItems(行选择)用户输入的有效目标恒为空(CanSelectRows=false)有效目标
SelectedCells ↔ SelectedItems只读镜像:选行后自动填充整行 Cells唯一选择状态,与行无关双向联动:取消任一 Cell 会取消其所在行

关键源码行为:

SelectionUnit 切换:全量清空(Full Wipe)

OnSelectionUnitChanged(DataGrid.cs:4470)做”全量清空”而非模式间转换:

// Full wipe on unit change
if (oldUnit != DataGridSelectionUnit.Cell)    { dataGrid.UnselectAll(); }
if (oldUnit != DataGridSelectionUnit.FullRow) { ...; dataGrid._selectedCells.Clear(); }
dataGrid.CoerceValue(IsSynchronizedWithCurrentItemProperty);

切换 SelectionUnit 会丢弃全部现有选择:旧单位支持行就 UnselectAll(),旧单位支持单元格就清空 _selectedCells,不会把行选择翻译成 cells 或反之。

与 SelectionMode 的组合

官方注释明确 “The SelectionMode and the SelectionUnit properties together define the selection behavior”(DataGrid.cs:4393)。OnSelectionModeChanged(DataGrid.cs:4408)切到 Single 时按 unit 决定保留哪个:

实践建议

图示

行为矩阵、核心类型类图与三种 SelectionUnit 的选择时序:

ref