30 KiB
DataGrid 桌面版架构设计
本文档定义 DataGrid 桌面版的最新设计定位、公共契约、状态模型、视觉主题关系和兼容边界。通用控件研发约束见 控件研发标准,内部实现原理见 DataGrid 桌面版实现原理,查询、范围数据源与虚拟化见 DataGrid Query 与 Range Source 设计,列宽测量与分配见 DataGrid 列宽分配设计,分页面板扩展区域见 DataGrid 分页面板 Extra Content 设计,DataGrid Token 的专项设计见 DataGrid Token 设计,设计和契约变化记录见 DataGrid Changelog。
该控件的 Popup 钉住打开属于共享弹层契约,详见 Popup 钉住打开设计。本控件的语义 owner 为 DataGrid,其 internal IsPopupPinnedOpen 只供测试和内部诊断使用;设置为 true 时按 DisplayIndex 选择第一个有效列过滤入口,并通过 Header、FilterIndicator 和 Flyout relay 到具体 Popup,设置为 false 时只解除关闭拦截。控件卸载、锚点失效、TopLevel 改变、目标列替换和模板重建仍按共享生命周期规则清理。
1. 控件定位
| 项 | 值 |
|---|---|
| NuGet 包 | AtomUI.Desktop.Controls.DataGrid |
| .NET 命名空间 | AtomUI.Desktop.Controls.DataGrid |
| AXAML 命名空间 | https://atomui.net |
| Gallery 页面 | controlgallery/AtomUIGallery/ShowCases/DataDisplay/DataGrid |
| 控件状态 | Stable |
DataGrid 是 AtomUI 桌面控件体系中的数据表格控件,用于列模型、行选择、排序、过滤、分组、编辑、冻结列、连续虚拟滚动和分页展示。本地集合与远端服务通过同一个范围数据源契约接入。
DataGrid 不负责简单列表、树视图或业务数据访问层。这些职责应由业务层、组合控件或更专用的 AtomUI 控件承担。
主要源码入口:
src/AtomUI.Desktop.Controls.DataGrid
2. 设计语言
DataGrid 的设计语言围绕控件职责、可观察状态和主题契约组织,而不是围绕模板节点组织。
| 维度 | 含义 | DataGrid 中的表达 |
|---|---|---|
| 产品语义 | 控件在界面中承担的稳定职责。 | DataGrid 以不可变 Query 描述数据语义,以 Range Source 支持本地或远端数据,并只物化当前视口。 |
| 内容承载 | 用户数据、展示内容、集合项或操作入口如何进入控件。 | ItemsSource : IDataGridSource?、Query、GroupExpansion、列 FieldId、CellTemplate 和 CellEditingTemplate。 |
| 状态反馈 | public API、内部状态和伪类如何形成用户可感知反馈。 | AppliedQuery、LoadState、Selection、CurrentRowKey、sort/filter/group projection、motion 和 visual option。 |
| 主题语义 | ControlTheme、SharedToken、Control Own Token 和模板绑定如何表达视觉。 | DataGrid Token + ControlTheme。 |
3. API 与契约模型
DataGrid 的公共契约由 public/protected 类型成员、Avalonia 属性、事件、命令、template part、伪类、ControlTheme key 和资源 key 共同组成。维护时应先确认这些契约是否已经被源码、Gallery 示例或文档暴露。
核心 public surface 按语义分组维护:
| 契约组 | 代表成员 | 维护含义 |
|---|---|---|
| 内容与数据 | ItemsSource、Query、AppliedQuery、GroupExpansion、TotalItemCount、TotalEntryCount、AutoGenerateColumns、CellTemplate、CellEditingTemplate |
定义数据输入、查询、范围 presentation、模板和业务对象入口;ItemsSource 的类型是 IDataGridSource?。 |
| 选择与当前项 | Selection、CurrentRowKey、SelectionChanged、ClipboardCopyMode |
以稳定 row key、query scope 和 index interval 维护可跨 range/page 的声明式状态。 |
| 交互与加载 | CanUserFilterColumns、CanUserReorderRows、CanUserResizeColumns、CanUserSortColumns、QueryChanged、LoadState、LoadError、IsDataStale、Reload() |
表达用户查询意图、异步生命周期、错误与可提交能力。 |
| 视觉与布局 | BottomPaginationAlign、ColumnWidth、HorizontalAlignment、HorizontalScrollBarVisibility、IsShowPageSizeSelector、MaxColumnWidth、MinColumnWidth、RowHeight、SeparatorBrush、SizeType、SublevelIndent 等 15 项 |
影响尺寸、位置、颜色、形状、密度和模板视觉变量。 |
| 分页面板扩展 | TopPaginationExtraContent、TopPaginationExtraContentTemplate、BottomPaginationExtraContent、BottomPaginationExtraContentTemplate |
在顶部/底部分页区域提供与 Pagination 相反一侧的独立 Extra Content;默认均为 null,不拥有分页状态。 |
| 列查询契约 | FieldId、CanUserSort、SupportedSortDirections、只读 SortState、过滤候选展示属性 |
让列声明协议字段与能力覆盖,显示 Binding 不参与查询 identity。 |
| 其他稳定入口 | CellTheme、CustomOperatingIndicator、EmptyIndicator、Footer、FormatString、GridLinesVisibility、Level、Maximum、Minimum 等 |
保留非数据架构 public surface,变更前需确认 Gallery 和用户 XAML 依赖。 |
ItemsSource 只接受 IDataGridSource?,不是旧集合型 IEnumerable 入口。本地集合使用 DataGridLocalSource.Create(...)
建立强类型 range source,远端实现使用同一接口翻译 Query 并按请求范围返回数据;DataGrid 不拥有或 dispose 外部 Source。
稳定事件包括 QueryChanged、SelectionChanged、RowReordering 和 RowReordered。QueryChanged 是不可取消的观察事件,在 Query 的内存提交与视觉投影之后、对应 Source 请求之前触发;其他事件的参数和触发顺序同样属于契约。
行拖动重排由 CanUserReorderRows、DataGridRowReorderColumn、RowReordering、RowReordered 和可选
IDataGridMovableSource 共同表达。DataGrid 使用 source row key 与目标 before/after key 提交移动,不把 view、window 或 display
索引解释为 Source 集合索引。Source 不支持移动、当前 Query 语义禁止移动、编辑未能提交或 snapshot 失效时,handle 不进入
可提交状态,也不发布 RowReordered。
分页公共契约由 PageSize、IsShowPageSizeSelector、PaginationVisibility、TopPaginationAlign、
BottomPaginationAlign 和 IsHideOnSinglePage 共同表达。IsShowPageSizeSelector 默认为 true,转发到顶部和底部
Pagination.IsShowSizeChanger;它只控制页大小选择器可见性,不创建独立的 DataGrid 页大小状态。PageSize=0 表示连续模式;
非零值形成 DataGridPageRequest,其中 data start 使用 long、单页 count 使用 int。分页总数只来自已提交 Source result 的
TotalDataCount,顶部和底部 Pagination 只投影同一份 applied page state。翻页成功后垂直 offset 归零;失败时页码、rows、
totals、scrollbar 和 Query 共同回退到最后成功 presentation。
分页面板可以在 Pagination 对侧提供 Extra Content。Start 对齐时 Pagination 左置、Extra Content 右置;End 对齐时
Extra Content 左置、Pagination 右置;Center 对齐时 Extra Content 右置,Pagination 在剩余区域内居中。顶部和底部
Extra Content 使用独立 Content/Template 属性,完整契约见 DataGrid 分页面板 Extra Content 设计。
列宽公共契约由 DataGrid.ColumnWidth、DataGridColumn.Width、控件级与列级最小/最大宽度,以及
DataGridLengthUnitType 共同表达。ColumnWidth 默认为 Auto;单列可以使用 Pixel、Auto、
SizeToHeader、SizeToCells 或 Star。内容驱动模式先形成期望宽度,star 模式再按权重分配有限列视口中的
剩余空间。列宽状态与统一分配算法由 DataGrid 持有,普通表头、分组表头和 rows/cells presenter 只提供当前
布局可证明的有限宽度或内容测量结果。空数据时列宽求解不能依赖已隐藏的 rows presenter,完整契约见
DataGrid 列宽分配设计。
列过滤候选项与过滤条件分离。列 Filters 只负责菜单或树形弹层中的候选内容,可以绑定 ViewModel 集合或数据库返回的
DTO;DataGrid.Query.Filters 是已应用条件的唯一 owner。Flyout checked state、FilterIndicator 激活态与 Source request 都从
Query 投影,用户确认后一次性生成新的不可变 Query。过滤 DTO 的显示成员可以使用 generated data member accessor;Query 中的
值则转换为确定性的 DataGridScalar,不保留可变 object、predicate 或反射 path。
过滤交互模式使用显式枚举表达:FilterPresenterMode 表达菜单或树形弹层,FilterSelectionMode 表达单选或多选,FilterApplyMode 表达确认、关闭或选择变化时应用过滤。枚举状态比布尔开关更适合作为长期 public API,因为它能把展示方式、选择方式和提交时机拆成三个正交状态,避免布尔组合在状态流中产生歧义。
主要公开类型与枚举:
- 类型:
DataGrid、DataGridQuery、IDataGridSource、DataGridSourceSchema、DataGridFieldSchema、DataGridFieldDisplayAccessor、DataGridRange、DataGridPageRequest、DataGridRangeResult、DataGridSelectionState、DataGridColumn、DataGridRow和DataGridCell等。 - 枚举:
DataGridSortDirection、DataGridSortUpdateMode、DataGridLoadState、DataGridSourceEntryKind、DataGridClipboardCopyMode、DataGridEditingUnit、DataGridLengthUnitType、DataGridPaginationVisibility和DataGridRowDetailsVisibilityMode等。
稳定 template part:
| Template Part | 类型 | 职责 |
|---|---|---|
PART_Ascending |
? |
稳定模板协作入口,重命名前必须同步主题和实现。 |
PART_BottomGridLine |
? |
稳定模板协作入口,重命名前必须同步主题和实现。 |
PART_BottomPaginationExtraContentPresenter |
ContentPresenter |
展示底部分页面板 Extra Content。 |
PART_BottomPaginationPanel |
DockPanel |
组合底部 Extra Content 与 Pagination,并执行相反侧对齐。 |
PART_BottomPagination |
Pagination |
投影 applied page state 并转发底部翻页意图。 |
PART_ColumnHeadersPresenter |
DataGridColumnHeadersPresenter |
测量普通列头,并在空数据布局中提供有限列视口宽度。 |
PART_ContentFrame |
? |
承载根视觉、边框、背景或尺寸基线。 |
PART_ContentPresenter |
? |
展示用户内容、文本、图标或模板化数据。 |
PART_Descending |
? |
稳定模板协作入口,重命名前必须同步主题和实现。 |
PART_FocusVisual |
? |
稳定模板协作入口,重命名前必须同步主题和实现。 |
PART_Frame |
? |
承载根视觉、边框、背景或尺寸基线。 |
PART_GroupColumnHeadersPresenter |
DataGridGroupColumnHeadersPresenter |
测量分组列头,并与普通列头共享列宽输入契约。 |
PART_HeaderPresenter |
? |
展示用户内容、文本、图标或模板化数据。 |
PART_HorizontalIndicator |
? |
展示指示器、进度、分页或状态反馈。 |
PART_IndicatorIconButton |
? |
承载用户触发入口、导航或关闭动作。 |
PART_ItemsPresenter |
? |
展示用户内容、文本、图标或模板化数据。 |
PART_RightGridLine |
? |
稳定模板协作入口,重命名前必须同步主题和实现。 |
PART_RootLayout |
? |
承载根视觉、边框、背景或尺寸基线。 |
PART_RowPresenter |
DataGridRowsPresenter |
承载已物化行;空数据时保持隐藏,不作为 star 求解的必要前置。 |
PART_SortIndicator |
? |
展示指示器、进度、分页或状态反馈。 |
PART_TopPaginationExtraContentPresenter |
ContentPresenter |
展示顶部分页面板 Extra Content。 |
PART_TopPaginationPanel |
DockPanel |
组合顶部 Extra Content 与 Pagination,并执行相反侧对齐。 |
PART_TopPagination |
Pagination |
投影 applied page state 并转发顶部翻页意图。 |
PART_VerticalIndicator |
? |
展示指示器、进度、分页或状态反馈。 |
PART_VerticalSeparator |
? |
稳定模板协作入口,重命名前必须同步主题和实现。 |
控件专属或内部伪类包括 DataGridPseudoClass.EmptyColumns、DataGridPseudoClass.EmptyRows、DataGridPseudoClass.FirstColumnHeader、DataGridPseudoClass.GroupItemLeaf、DataGridPseudoClass.LastColumnHeader、DataGridPseudoClass.MiddleColumnHeader、DataGridPseudoClass.RowHover、EmptyColumns=:empty-columns、EmptyRows=:empty-rows、FirstColumnHeader=:first-column-header、GroupItemLeaf=:is-leaf-item、LastColumnHeader=:last-column-header 等 14 项。这些伪类属于主题 selector 可观察契约,不能在未同步主题和 Gallery 的情况下重命名或删除。
4. 行为与状态模型
DataGrid 的状态流按以下路径收敛:
Public API / inherited command / Source invalidation / user input
-> 控件实例状态
-> effective state / pseudo-class / template property
-> ControlTheme selector / presenter / renderer
-> Gallery 可观察行为
状态维护规则:
- Disabled 或不可交互状态优先屏蔽 pointer、keyboard、motion 和提交类反馈。
- Query、Selection、current、loading、motion 和 visual option 状态由 DataGrid 或明确 Source capability 单向推导,不能在 template part 之间双向竞争。
- 排序、过滤和分组只由
Query拥有;列、Header、Cell 和 Flyout 只投影相应字段状态。 Filters候选项替换、reset 或 clear 时可以重新物化 Flyout 内容,但不能直接改变已应用 Query;用户确认或显式 API 才提交新的 Query。- 分页状态以 applied PageRequest 和
TotalItemCount为 owner;页大小选择器的输入转换为新的DataGridPageRequest,保持可保留的页序号并在新页数不足时收敛到最后一页。上下 Pagination 不能互相覆盖,也不能在模板重建时反向重置 Query 或 Source。 - Extra Content 只属于 DataGrid 分页面板,不参与 Query、PageRequest、PageSize 或 Source request。它与内部 Pagination 共享有效可见性,不能在单页隐藏或连续模式下独立残留。
- Loading 没有可展示的已提交 presentation,实际挂起时驱动 Spin;Refreshing 保持旧 presentation 的几何与完整不透明度, 不自动启动 Spin。两种状态都禁止 edit/delete/move,成功时原子交换,失败时完整回退。
- 连续滚轮、惯性或 scrollbar thumb 输入只保留最新有效
DesiredViewport。新目标先接管仍需要的 block,再使旧视口 scope 失效;不再被任何有效 scope 使用的排队或执行中请求立即收到取消,旧 prefetch 不能排在新 visible range 之前。 - 同步 Source 与 cache hit 在当前调用中直接进入 Ready,不发布瞬时 Loading/Refreshing;调用方显式设置
IsOperating=true时仍可在任意 LoadState 显示 Spin。 - 行拖动状态以当前
DataGrid的单一拖拽会话为 owner;handle 和 RowsPresenter 只投影输入与 ghost row,不能保存 跨 DataGrid 共享的静态拖拽状态。Pointer capture、源 row key、Source snapshot 和目标邻接 key 必须属于同一个会话。 RowReordering在超过拖动阈值后且创建 ghost row 前触发一次;事件取消或事件回调改变 DataGrid、源行、 Source、Query、snapshot 或移动能力时,本次 Pointer 会话保持取消状态,不得在后续移动帧重复开始。RowReordered只在 movable Source 成功提交顺序变化,并且 ghost、capture、动画与会话状态全部清理后触发。- 模板重套用时必须把 public API 对应状态回放到新的 part、伪类和主题变量。
- 集合、弹层、异步、动效或窗口相关状态必须能处理 reset、close、cancel、detach 和 owner 释放。
5. 视觉与主题模型
DataGrid 的视觉模型由控件模板、ControlTheme、SharedToken 和 DataGrid Own Token 共同构成。
| 主题文件 | 职责 |
|---|---|
DataGridCellTheme.axaml |
定义集合项、容器项或局部单元的状态视觉。 |
DataGridColumnGroupHeaderTheme.axaml |
定义集合项、容器项或局部单元的状态视觉。 |
DataGridColumnHeaderTheme.axaml |
定义集合项、容器项或局部单元的状态视觉。 |
DataGridHeaderViewItemTheme.axaml |
定义集合项、容器项或局部单元的状态视觉。 |
DataGridOperationButtons.axaml |
定义局部操作入口、按钮或 handle 的状态视觉。 |
DataGridRowExpanderTheme.axaml |
定义集合项、容器项或局部单元的状态视觉。 |
DataGridRowGroupHeaderTheme.axaml |
定义集合项、容器项或局部单元的状态视觉。 |
DataGridRowHeaderTheme.axaml |
定义集合项、容器项或局部单元的状态视觉。 |
DataGridRowReorderHandle.axaml |
定义集合项、容器项或局部单元的状态视觉。 |
DataGridRowTheme.axaml |
定义集合项、容器项或局部单元的状态视觉。 |
DataGridTheme.axaml |
提供控件模板、selector、资源绑定和状态视觉。 |
DataGridTopLeftColumnHeaderTheme.axaml |
定义集合项、容器项或局部单元的状态视觉。 |
DataGridFilterIndicatorTheme.axaml |
提供控件模板、selector、资源绑定和状态视觉。 |
DataGridFilterMenuItemTheme.axaml |
定义集合项、容器项或局部单元的状态视觉。 |
DataGridFilterTreeItemTheme.axaml |
定义集合项、容器项或局部单元的状态视觉。 |
DataGridMenuFilterFlyoutPresenterTheme.axaml |
定义弹层、窗口或 overlay 宿主视觉。 |
DataGridSortIndicatorTheme.axaml |
提供控件模板、selector、资源绑定和状态视觉。 |
DataGridTreeFilterFlyoutPresenterTheme.axaml |
定义弹层、窗口或 overlay 宿主视觉。 |
DataGrid 拥有独立 Control identity;DataGridToken 只表达 DataGrid Own Token 语义,不承载 selection/checked/active、collection/filter、motion 或 visual option 运行时状态。Control 级 Global Token 覆盖与 Own Token 通过 DataGridTokenResource 统一读取。
主题维护规则:
- 不删除或重命名已经稳定的 ControlTheme key、template part、伪类和资源 key。
- 不把可由 AXAML 表达的模板状态迁移为 C# 动态创建视觉。
- 不把 hover、pressed、selected、expanded、loading、filter、popup open 等运行时状态写入 Token。
- Browser 或平台特化主题必须保持同一 API 的语义一致。
6. 控件家族或集成关系
DataGrid 与同分类控件共享尺寸、状态、Token、Gallery 展示和验证规则。组合或派生控件应显式说明哪些 API 被继承、覆盖或不支持。
主要协作类型:
DataGrid:public data/query/selection API、模板生命周期和 presentation transition 的 owner。DataGridQueryController:不可变 Query validation、revision、交互策略与观察事件的 owner。IDataGridSource:schema、范围读取、snapshot 和 invalidation 的数据边界。DataGridRangeCoordinator:generation、最新视口 scope、前台/预取调度、请求取消、block lease、pending cache、错误和原子提交的 owner。DataGridPresentationIndex:display slot、window data index、range block 与高度元数据的映射 owner。DataGridDisplayData:committed row/group container、循环显示列表和回收池的 owner。DataGridRowsPresenter:已提交纵向 viewport 的同步布局和IChildIndexProvider投影。DataGridColumn:FieldId、列级查询能力和 SortState 投影。DataGridColumnHeader、DataGridFilterIndicator与 filter Flyout:Query intent 和视觉状态的交互/模板投影。DataGridCellsPresenter:可见列、冻结列和横向 cell virtualization 的 owner。DataGridLocalSource<T>:强类型本地 query projection 和 range materialization。DataGridFieldDisplayAccessor:schema 中可选的 AOT-safe 显示访问;自动列只据此创建 compiled binding,FieldId 不作为属性路径。- 可选 editable、movable、key-lookup 与 bulk-selection Source 接口:未加载数据上的明确能力边界。
集成关系:
- 与 ThemeManager、SharedToken、ControlTheme、控件文档和 Gallery ShowCase 示例保持一致。
- 涉及 Source、Popup、Flyout、Window、Form 或 CompactSpace 的路径必须保持生命周期释放和数据状态同步。
- 源码目录中的共享基类和内部协作类型形成维护边界,不能只修改桌面包装类而忽略共享状态 owner。
7. 兼容性不变量
维护 DataGrid 时必须保持以下不变量:
ItemsSource、Query、Selection和可选 Source capability 的 identity 与 ownership 不能被模板或 presenter 改写。- 不破坏 template part、伪类、ControlTheme key、Token 名称和资源 key。
- Ready 状态的视觉树、尺寸、列宽、滚动条、冻结列、RowDetails、selected/sorted 优先级和嵌套滚动链保持稳定。
- Template part 重新应用、Source 替换、弹层关闭、窗口失活和控件 detach 时必须释放旧订阅、请求、cache 和资源宿主。
- 不通过隐藏延迟、强制刷新、ignore flag 或吞异常掩盖状态同步问题。
- 不引入运行时反射扫描作为 API、Token 或数据路径发现机制。
- Source result 必须满足精确切片、snapshot、totals、key 唯一性和 index mapping 合同;无效结果不得部分显示。
- Source 必须协作处理 FetchAsync 的 CancellationToken 才能获得快速跳转的低延迟保证;无论 Source 是否协作,旧 viewport 结果 都不能覆盖最新 presentation,DataGrid 也不能突破有界并发掩盖不可抢占 I/O。
- 连续模式超出 int presentation 上限时明确失败;分页通过 long data start 访问更大数据,不截断或饱和索引。
- Measure、Arrange、container prepare/recycle 和 input handler 不执行 Source I/O 或同步等待。
- 未声明 movable capability 时安全拒绝移动,不能错误提交、部分提交或发出成功事件。
- 文档只描述当前稳定设计;历史变化记录在
changelog.md。
8. 专项模型
8.1 选择与当前项模型
DataGridSelectionState 是不可变选择 owner,使用 ExplicitKeys、AllMatchingQuery、IndexIntervals 与 ExcludedKeys 表达单行、
跨页全选和范围选择。容器只按 RowKey/DataIndex 投影状态;回收不会改变选择。CurrentRowKey 是 current identity,internal
DataIndex hint 只用于定位。Source replacement 清空 selection/current;Query 与 invalidation 按
Query 与 Range Source 设计定义确定的保留和失效规则。
8.2 集合与数据同步模型
DataGrid 的数据状态遵循单一路径:
immutable Query
-> QueryController revision
-> RangeCoordinator request/cache
-> validated Source snapshot
-> atomic PresentationSnapshot
-> realized containers
Source replacement、Invalidated、Reload、Query、PageRequest 和 GroupExpansion 通过单调 revision/generation 隔离迟到结果。
DesiredViewport 与 CommittedViewport 分离;每个 generation 同时只有一个活动 viewport scope,scope 通过 block lease 保留新旧
目标仍共享的请求,并取消已经离开最新目标的 visible/prefetch 工作。自动行高估值也由 committed generation 所有:成功切换
generation 后重新采样,pending/失败状态继续使用旧 presentation 的估值。layout 只读取已提交并 pin 的 range block。完整 Source、
snapshot、请求优先级、缓存、索引域、虚拟化和回滚合同见
DataGrid Query 与 Range Source 设计。
8.3 行拖动重排模型
行拖动重排采用“控件会话负责交互、movable Source 负责数据提交”的单向模型:
PointerPressed
-> DataGrid row reorder session (Pressed)
-> DragThreshold
-> RowReordering
-> session validation
-> RowsPresenter ghost row (Dragging)
-> IDataGridMovableSource move by row/neighbor keys + snapshot
-> session cleanup
-> RowReordered
每个 DataGrid 同时最多拥有一个行拖动会话。会话跟踪 Pointer、源 handle、源 row、Source identity、snapshot、
源 RowKey、目标邻接 key 和拖动几何。Pointer 不匹配、capture 丢失、控件禁用、CanUserReorderRows=false、
Source、Query 或 snapshot 替换、行回收、重排列移除、模板重建或 DataGrid detach
都会取消会话。取消和完成共用同一个清理边界,必须移除 ghost row、恢复动效、释放 capture 并清除会话引用。
移动提交由 Source 维护自己的数据、snapshot 和 invalidation。DataGrid 不推断 Source 集合结构,也不把 display/window index 当作数据索引。Source 不支持移动时,handle 不进入可提交的 Dragging 状态。异常路径先无条件清理视觉会话,且不能留下 ghost row、旧 key 或成功事件。
8.4 列过滤模型
列过滤模型由三层组成:
Column.Filters / filter presentation metadata
-> Query intent
-> DataGrid.Query.Filters
Filters 只表达候选过滤项来源;DataGrid.Query.Filters 表达已应用条件。DataGridFilterIndicator、菜单 flyout 和树形 flyout
是 Query 的视觉投影,不拥有业务状态。它们打开或重新物化时按 Query 初始化 checked state,在确认时构建一个已验证的
不可变 Query。Source schema 声明 operator、arity 和 scalar kinds;LocalSource descriptor 提供 typed evaluator,远端 Source
显式翻译 operator,DataGrid 不猜测字符串匹配规则。
DataGrid 的 internal pinned filter 只选择一个目标,目标顺序来自 ColumnsInternal.GetDisplayedColumns(),即当前
DisplayIndex 顺序。候选列必须不是 filler、可见、允许过滤、具有过滤项并已创建 Header;前一目标因 DisplayIndex、
可见性、CanUserFilter、过滤项或列集合变化而失效时,先对旧 Header 执行 lifecycle close 和 unpin,再 pin 新目标。
Pinned 状态只沿以下单向路径传播:
DataGrid
-> DataGridColumnHeader
-> DataGridFilterIndicator
-> DataGridMenuFilterFlyout / DataGridTreeFilterFlyout
-> Popup
Header 和 Indicator 都是 internal relay adapter,不成为第二个测试入口,也不拥有过滤业务状态。Unpin 只解除当前 Flyout 的关闭拦截;目标替换、Header/Indicator detach、Flyout presenter mode replacement、DataGrid detach 和 template reapply 必须强制关闭旧 Popup 并释放两级 relay。
8.5 列宽分配模型
列宽采用“presenter 提供几何输入,DataGrid 统一求解,所有视觉消费同一结果”的单向模型:
header / rows / cells available width and content measure
-> DataGrid column sizing state
-> constrained Auto completion and star distribution
-> DataGridColumn display widths
-> header / row / cell / filler / scrollbar projection
有已物化行时,rows/cells 路径提供包含行头和滚动布局修正后的 CellsWidth;空数据时,当前可见的普通或分组
列头 presenter 使用自己的有限测量宽度驱动同一个求解器。AutoSizingColumns 只表示初始内容测量阶段,完成
Auto 测量和分配 star 剩余空间是两个独立职责。filler 只承载所有可调整列达到 min/max 约束后仍无法分配的正
剩余空间,不能替代 star 列分配。
range source、分页和纵向虚拟化只让已实现 cells 参与 Auto / SizeToCells 测量;DataGrid 不为发现未加载内容宽度而请求其他 range。需要首屏稳定且保留内容宽度的水平 extent 时,应由列的 Pixel Width 或 MinWidth 明确提供几何基线,而不是扫描其他页、改用会压缩内容的 Star,或强制显示没有真实 overflow 的 scrollbar。
8.6 动效模型
DataGrid 的动效只表达状态变化反馈,不应改变 public API 语义。初始加载、禁用态和卸载路径应能抑制或取消动效,避免保留旧控件实例。
8.7 视觉选项模型
DataGrid 的视觉选项通过 public API 归一为 theme variables、伪类或模板绑定。Token 保存组件语义值,不能保存实例运行时状态或业务色值。
9. 文档导航与验证策略
关联文档:
- DataGrid 桌面版实现原理
- DataGrid Query 与 Range Source 设计
- DataGrid 列宽分配设计
- DataGrid Token 设计
- DataGrid Changelog
映射取舍:
- AntD
header.row(thead 的 tr)在 AtomUI 中没有独立节点:DataGridColumnHeadersPresenter直接承载各列头,因此不声明header.row,避免虚构不存在的结构。 DataGridRowHeader(行头)无 AntD 对应物,不纳入语义部件。- 过滤/排序浮层属于列头触发的 Flyout 内容,遵循共享弹层契约,不在 Table 语义区域内声明。
验证策略:
| 改动类型 | 验证要求 |
|---|---|
| 文档改动 | 运行 git diff --check,检查相对链接存在。 |
| Public API | 覆盖属性默认值、事件触发、命令和继承语义。 |
| 状态模型 | 覆盖 selection/checked/active、collection/filter、motion、visual option、disabled、hover、pressed、focus 以及控件特有状态。 |
| AXAML/Theme | 检查 template part、伪类、资源 key、Light/Dark 主题和 Browser 主题。 |
| Token | 检查 TokenKind、AXAML token resource、Token 类型、生成数据和 token.md和文档同步。 |
| Gallery | 走查对应 ShowCase 示例和源码片段入口。 |