Commit Graph
283 Commits
Author SHA1 Message Date
chinboy 915deff4eb perf(controls): reduce allocation and state sync overhead 2026-05-29 17:40:13 +08:00
chinboy 6f4bbdc064 perf(controls): reduce transfer, tree and layout overhead 2026-05-29 10:32:40 +08:00
chinboy 9b83aa5940 perf(PopupConfirm): optimize button event lifecycle and correctness 2026-05-28 23:08:04 +08:00
chinboy 4a60c55fc2 perf(controls): optimize flyout and layout lifecycles 2026-05-28 21:48:10 +08:00
chinboy 9379c9a0c5 perf(controls): optimize ColorPicker, titlebar and adorner lifecycles 2026-05-28 11:50:30 +08:00
chinboy 8974f9cf6f docs(DataGrid): close remaining performance audit items 2026-05-28 10:01:41 +08:00
chinboy 3eefb30d8b perf(DataGrid): reduce data-layer and column group overhead 2026-05-28 09:13:01 +08:00
chinboy c621706a52 perf(DataGrid): add verification for item-type probe enumerator disposal 2026-05-27 15:55:41 +08:00
chinboy 393b376189 perf(DataGrid): reduce filter and data-layer overhead 2026-05-27 15:32:01 +08:00
chinboy d55bc01c52 perf(DataGrid): reduce allocation and lifecycle overhead 2026-05-26 19:38:27 +08:00
chinboy a4e07782fa perf(DataGrid): reuse row group header transforms
Cache DataGridRowGroupHeader frozen child TranslateTransform instances across repeated arrange passes, update X in place, and clear child RenderTransform values when row group headers become fully frozen, re-templated, or detached.

Qualification: DataGridShowCase declares 65 DataGrid instances; grouped grids with row headers and horizontal scrolling exercise row group header frozen child arrange paths. Operation frequency: horizontal scrolling, row group header layout, row group header frozen-state changes, re-template, and detach.

Avalonia basis: Visual.RenderTransform is a styled property and Avalonia subscribes mutable Transform.Changed to invalidate the visual (.referenceprojects/Avalonia/src/Avalonia.Base/Visual.cs:92-100,150,644-710). TranslateTransform.X/Y changes raise Transform.Changed (.referenceprojects/Avalonia/src/Avalonia.Base/Media/TranslateTransform.cs:14-22,70-75; .referenceprojects/Avalonia/src/Avalonia.Base/Media/Transform.cs:23-50).

Verification: dotnet build -c Release -f net10.0 tools/performances/AtomUI.Performance/AtomUI.Performance.csproj; dotnet run -c Release -f net10.0 --no-build --project tools/performances/AtomUI.Performance/AtomUI.Performance.csproj -- --verify-datagrid-states; dotnet run -c Release -f net10.0 --no-build --project tools/performances/AtomUI.Performance/AtomUI.Performance.csproj -- --suite datagrid --count 100; git diff --check; git diff --cached --check.
2026-05-26 10:37:47 +08:00
chinboy 2f41df5b7c perf(DataGrid): reduce row clip allocation
Reuse DataGridRow hidden clip geometry for non-recyclable hidden rows and cache DataGridRowGroupHeader child clip geometries across repeated arrange passes. Also resolve the built-in RowGroupHeader RootLayout/RowHeader template part names so row header visibility, owner wiring, and child clip lifecycle run for the shipped template.

Qualification: DataGridShowCase declares 65 DataGrid instances; row virtualization/removal paths apply to realized rows, and row group header child clipping applies to grouped grids with row headers/frozen offsets. Operation frequency: vertical scrolling, ItemsSource changes, row deletion, row clearing, horizontal scrolling, row group header layout, re-template, and detach.

Avalonia basis: Visual.Clip is a styled property registered with AffectsRender and InvalidateVisual queues dirty rendering (.referenceprojects/Avalonia/src/Avalonia.Base/Visual.cs:52-53,141-149,418-421,446-500). RectangleGeometry.RectProperty marks geometry dirty (.referenceprojects/Avalonia/src/Avalonia.Base/Media/RectangleGeometry.cs:25-33; .referenceprojects/Avalonia/src/Avalonia.Base/Media/Geometry.cs:146-172).

Verification: dotnet build -c Release -f net10.0 tools/performances/AtomUI.Performance/AtomUI.Performance.csproj; dotnet run -c Release -f net10.0 --no-build --project tools/performances/AtomUI.Performance/AtomUI.Performance.csproj -- --verify-datagrid-states; dotnet run -c Release -f net10.0 --no-build --project tools/performances/AtomUI.Performance/AtomUI.Performance.csproj -- --suite datagrid --count 100; git diff --check; git diff --cached --check.
2026-05-26 10:12:26 +08:00
chinboy 2925af953f perf(DataGrid): reduce reordering indicator clip allocation
Gallery qualification: DataGridShowCase declares 65 DataGrid instances and 210 column declarations. Column reordering is available on the column header presenters, and the optimized path applies to drag and drop-location indicators clipped by frozen column regions during standard and grouped header reordering.

Operation frequency: column reordering indicator arrange/clip updates can run during pointer move, auto-scroll, horizontal scrolling, resizing, and grid relayout while a column is being dragged. Previously each clipped indicator update allocated a new RectangleGeometry.

Avalonia source basis: Visual.Clip is a styled property registered with AffectsRender, and InvalidateVisual marks the visual dirty (.referenceprojects/Avalonia/src/Avalonia.Base/Visual.cs:52-53,141-149,418-421,446-500). RectangleGeometry.Rect participates in geometry invalidation (.referenceprojects/Avalonia/src/Avalonia.Base/Media/RectangleGeometry.cs:25-33; .referenceprojects/Avalonia/src/Avalonia.Base/Media/Geometry.cs:146-172).

Benefit: repeated clipped column reordering indicator updates now reuse cached RectangleGeometry instances after first use, reducing repeated clip geometry allocation from 1/clipped indicator update to 0 after first while preserving Clip clearing when clipping is no longer needed or an indicator is replaced.

Verification: dotnet build -c Release -f net10.0 tools/performances/AtomUI.Performance/AtomUI.Performance.csproj; dotnet run -c Release -f net10.0 --no-build --project tools/performances/AtomUI.Performance/AtomUI.Performance.csproj -- --verify-datagrid-states; dotnet run -c Release -f net10.0 --no-build --project tools/performances/AtomUI.Performance/AtomUI.Performance.csproj -- --suite datagrid --count 100; git diff --check.
2026-05-26 09:29:10 +08:00
chinboy e64267c11f perf(DataGrid): reduce group header clip allocation
Gallery qualification: DataGridShowCase declares 65 DataGrid instances and 210 column declarations. Grouped header scenarios include DataGridColumnGroupItem leaves, and frozen-column examples use LeftFrozenColumnCount and RightFrozenColumnCount. The optimized path applies to grouped leaf DataGridHeaderViewItem instances that require clipping under frozen columns.

Operation frequency: group column header presenter arrange runs during initial layout, horizontal scrolling, resizing, column width changes, and grid relayout. Previously each clipped grouped leaf header arrange allocated a new RectangleGeometry.

Avalonia source basis: Visual.Clip is a styled property registered with AffectsRender, and InvalidateVisual marks the visual dirty (.referenceprojects/Avalonia/src/Avalonia.Base/Visual.cs:52-53,141-149,418-421,446-500). RectangleGeometry.Rect participates in geometry invalidation (.referenceprojects/Avalonia/src/Avalonia.Base/Media/RectangleGeometry.cs:25-33; .referenceprojects/Avalonia/src/Avalonia.Base/Media/Geometry.cs:146-172).

Benefit: repeated clipped group column header view item arrange now reuses one RectangleGeometry after first use, reducing repeated clip geometry allocation from 1/clipped grouped leaf header arrange to 0 after first while preserving Clip clearing when clipping is no longer needed.

Verification: dotnet build -c Release -f net10.0 tools/performances/AtomUI.Performance/AtomUI.Performance.csproj; dotnet run -c Release -f net10.0 --no-build --project tools/performances/AtomUI.Performance/AtomUI.Performance.csproj -- --verify-datagrid-states; dotnet run -c Release -f net10.0 --no-build --project tools/performances/AtomUI.Performance/AtomUI.Performance.csproj -- --suite datagrid --count 100; git diff --check.
2026-05-26 08:59:59 +08:00
chinboy a58b30355d perf(DataGrid): reduce column header clip allocation
Gallery qualification: DataGridShowCase declares 65 DataGrid instances and 210 column declarations, including multiple frozen-column examples with LeftFrozenColumnCount and RightFrozenColumnCount. The optimized path applies to realized DataGridColumnHeader instances that require clipping under frozen columns or header viewport constraints.

Operation frequency: column header presenter arrange runs during initial layout, horizontal scrolling, resizing, column width changes, and grid relayout. Previously each clipped header arrange allocated a new RectangleGeometry.

Avalonia source basis: Visual.Clip is a styled property registered with AffectsRender, and InvalidateVisual marks the visual dirty (.referenceprojects/Avalonia/src/Avalonia.Base/Visual.cs:52-53,141-149,418-421,446-500). RectangleGeometry.Rect participates in geometry invalidation (.referenceprojects/Avalonia/src/Avalonia.Base/Media/RectangleGeometry.cs:25-33; .referenceprojects/Avalonia/src/Avalonia.Base/Media/Geometry.cs:146-172).

Benefit: repeated clipped column header arrange now reuses one RectangleGeometry after first use, reducing repeated clip geometry allocation from 1/clipped header arrange to 0 after first while preserving Clip clearing when clipping is no longer needed.

Verification: dotnet build -c Release -f net10.0 tools/performances/AtomUI.Performance/AtomUI.Performance.csproj; dotnet run -c Release -f net10.0 --no-build --project tools/performances/AtomUI.Performance/AtomUI.Performance.csproj -- --verify-datagrid-states; dotnet run -c Release -f net10.0 --no-build --project tools/performances/AtomUI.Performance/AtomUI.Performance.csproj -- --suite datagrid --count 100; git diff --check.
2026-05-26 08:47:23 +08:00
chinboy d827dd12f7 perf(DataGrid): reduce cell clip allocation
Gallery qualification: DataGridShowCase declares 65 DataGrid instances, including multiple frozen-column examples with LeftFrozenColumnCount and RightFrozenColumnCount. The optimized path applies to realized DataGridCell instances that require clipping under frozen columns or horizontal virtualization.

Operation frequency: cells presenter arrange runs during initial layout, horizontal scrolling, resizing, column width changes, grid relayout, and row virtualization reuse. Previously each clipped cell arrange allocated a new RectangleGeometry.

Avalonia source basis: Visual.Clip is a styled property registered with AffectsRender, and InvalidateVisual marks the visual dirty (.referenceprojects/Avalonia/src/Avalonia.Base/Visual.cs:52-53,141-149,418-421,446-500). RectangleGeometry.Rect participates in geometry invalidation (.referenceprojects/Avalonia/src/Avalonia.Base/Media/RectangleGeometry.cs:25-33; .referenceprojects/Avalonia/src/Avalonia.Base/Media/Geometry.cs:146-172).

Benefit: repeated clipped cell arrange now reuses one RectangleGeometry after first use, reducing repeated clip geometry allocation from 1/clipped cell arrange to 0 after first while preserving Clip clearing when clipping is no longer needed.

Verification: dotnet build -c Release -f net10.0 tools/performances/AtomUI.Performance/AtomUI.Performance.csproj; dotnet run -c Release -f net10.0 --no-build --project tools/performances/AtomUI.Performance/AtomUI.Performance.csproj -- --verify-datagrid-states; dotnet run -c Release -f net10.0 --no-build --project tools/performances/AtomUI.Performance/AtomUI.Performance.csproj -- --suite datagrid --count 100; git diff --check.
2026-05-26 08:15:39 +08:00
chinboy 2c47bce767 perf(DataGrid): reduce details presenter clip allocation
Gallery qualification: DataGridShowCase declares 65 DataGrid instances. Row details scenarios create DataGridDetailsPresenter per templated row, but this allocation path only applies to visible non-frozen row details during arrange.

Operation frequency: visible row details arrange during initial layout, horizontal scrolling, resizing, grid relayout, and row details visibility/frozen-state changes.

Avalonia source basis: Visual.Clip is a styled property registered with AffectsRender, and InvalidateVisual marks the visual dirty (.referenceprojects/Avalonia/src/Avalonia.Base/Visual.cs:52-53,141-149,418-421,446-500). RectangleGeometry.Rect participates in geometry invalidation (.referenceprojects/Avalonia/src/Avalonia.Base/Media/RectangleGeometry.cs:25-33; .referenceprojects/Avalonia/src/Avalonia.Base/Media/Geometry.cs:146-172).

Benefit: repeated non-frozen details arrange now reuses one RectangleGeometry after first use, reducing repeated clip geometry allocation from 1/details arrange to 0 after first while preserving frozen Clip clearing.

Verification: dotnet build -c Release -f net10.0 tools/performances/AtomUI.Performance/AtomUI.Performance.csproj; dotnet run -c Release -f net10.0 --no-build --project tools/performances/AtomUI.Performance/AtomUI.Performance.csproj -- --verify-datagrid-states; dotnet run -c Release -f net10.0 --no-build --project tools/performances/AtomUI.Performance/AtomUI.Performance.csproj -- --suite datagrid --count 100; git diff --check.
2026-05-26 07:42:44 +08:00
chinboy 5e366bb34a perf(DataGrid): reduce row gridline clip allocation
Gallery qualification: DataGridShowCase declares 65 DataGrid instances; each realized DataGrid creates multiple DataGridRow instances, and every templated row owns one PART_BottomGridLine.

Operation frequency: DataGridRow.ArrangeOverride runs during page navigation layout, resizing, horizontal scrolling, row recycling, and grid relayout; the previous code allocated one RectangleGeometry for the bottom gridline on each realized row arrange.

Avalonia basis: Visual.Clip is a StyledProperty registered with AffectsRender and InvalidateVisual queues the visual for repaint (.referenceprojects/Avalonia/src/Avalonia.Base/Visual.cs:52-53,141-149,418-421). RectangleGeometry.RectProperty is registered with AffectsGeometry, so the reused geometry updates its platform geometry while this change explicitly invalidates the bottom gridline when Rect changes (.referenceprojects/Avalonia/src/Avalonia.Base/Media/RectangleGeometry.cs:25-33; .referenceprojects/Avalonia/src/Avalonia.Base/Media/Geometry.cs:146-172).

Verification: dotnet build -c Release -f net10.0 tools/performances/AtomUI.Performance/AtomUI.Performance.csproj; dotnet run -c Release -f net10.0 --no-build --project tools/performances/AtomUI.Performance/AtomUI.Performance.csproj -- --verify-datagrid-states; dotnet run -c Release -f net10.0 --no-build --project tools/performances/AtomUI.Performance/AtomUI.Performance.csproj -- --suite datagrid --count 100.
2026-05-26 07:23:33 +08:00
chinboy cd9613d0bc perf(DataGrid): reduce rows presenter clip allocation
Gallery qualification: DataGridShowCase declares 65 DataGrid instances, and each realized DataGrid template owns one DataGridRowsPresenter.

Operation frequency: DataGridRowsPresenter.ArrangeOverride runs during page navigation layout, resizing, and scroll-triggered layout passes; the previous code allocated one RectangleGeometry per arrange.

Avalonia basis: Visual.Clip is a StyledProperty registered with AffectsRender and InvalidateVisual queues the visual for repaint (.referenceprojects/Avalonia/src/Avalonia.Base/Visual.cs:52-53,141-149,418-421). RectangleGeometry.RectProperty is registered with AffectsGeometry, so the reused geometry updates its platform geometry while this change explicitly invalidates the presenter when Rect changes (.referenceprojects/Avalonia/src/Avalonia.Base/Media/RectangleGeometry.cs:25-33; .referenceprojects/Avalonia/src/Avalonia.Base/Media/Geometry.cs:146-172).

Verification: dotnet build -c Release -f net10.0 tools/performances/AtomUI.Performance/AtomUI.Performance.csproj; dotnet run -c Release -f net10.0 --no-build --project tools/performances/AtomUI.Performance/AtomUI.Performance.csproj -- --verify-datagrid-states; dotnet run -c Release -f net10.0 --no-build --project tools/performances/AtomUI.Performance/AtomUI.Performance.csproj -- --suite datagrid --count 100.
2026-05-26 07:10:17 +08:00
chinboy db61a51160 perf(DataGrid): reduce rows presenter scroll handler overhead
Gallery qualification: DataGridShowCase declares 65 DataGrid instances, and each template creates one DataGridRowsPresenter. This removes one constructor-time local ScrollGesture routed subscription per rows presenter. Setup happens whenever a DataGrid template is realized; ScrollGesture runs when users scroll DataGrid rows with touchpad or gesture input.

Behavior: DataGridRowsPresenter now handles ScrollGesture through a class handler and still calls the existing OwningGrid.UpdateScroll(-e.Delta) path. State verification confirms no local ScrollGesture handler remains, the gesture is still marked handled when scrolling occurs, and VerticalOffset still changes.

Documentation: updates the DataGrid performance notes and roadmap, and adds the performance-skill rule that every optimization completion must proactively report benefit in a table with baseline, optimized, formula, improvement, and conclusion.

Avalonia basis: ScrollGestureEvent is a bubble routed event. Event adders call AddHandler and store local routed subscriptions in Interactive._eventHandlers, while AddClassHandler subscribes once through RoutedEvent.Raised and filters by route/type.

Sources: .referenceprojects/Avalonia/src/Avalonia.Base/Input/InputElement.Gestures.cs:65-69; .referenceprojects/Avalonia/src/Avalonia.Base/Input/InputElement.Gestures.cs:197-200; .referenceprojects/Avalonia/src/Avalonia.Base/Interactivity/Interactive.cs:30-64; .referenceprojects/Avalonia/src/Avalonia.Base/Interactivity/Interactive.cs:176-190; .referenceprojects/Avalonia/src/Avalonia.Base/Interactivity/RoutedEvent.cs:78-99.
2026-05-26 06:53:44 +08:00
chinboy bb5811bb63 perf(DataGrid): reduce core input handler overhead
Gallery qualification: DataGridShowCase declares 65 DataGrid instances, so constructor-time subscriptions are multiplied during page navigation and Gallery setup. This change removes four core input routed subscriptions per grid instance. Setup happens whenever a DataGrid is constructed; KeyDown, KeyUp, GotFocus, and LostFocus run during keyboard navigation and focus movement inside the grid.

Behavior: DataGrid now uses OnKeyDown, OnKeyUp, OnGotFocus, and OnLostFocus overrides to call the existing handler bodies with the same !Handled guard. State verification confirms the grid no longer has local core input handlers, GotFocus still updates ContainsFocus, and Down key navigation still moves the current slot.

Avalonia basis: InputElement registers class handlers that dispatch GotFocus, LostFocus, KeyDown, and KeyUp to the virtual OnGotFocus, OnLostFocus, OnKeyDown, and OnKeyUp methods. Event adders call AddHandler and store per-instance subscriptions in Interactive._eventHandlers; RoutedEvent.AddClassHandler uses RoutedEvent.Raised and route filtering.

Sources: .referenceprojects/Avalonia/src/Avalonia.Base/Input/InputElement.cs:235-240; .referenceprojects/Avalonia/src/Avalonia.Base/Input/InputElement.cs:596-657; .referenceprojects/Avalonia/src/Avalonia.Base/Input/InputElement.cs:106-118; .referenceprojects/Avalonia/src/Avalonia.Base/Interactivity/Interactive.cs:30-64; .referenceprojects/Avalonia/src/Avalonia.Base/Interactivity/Interactive.cs:176-190; .referenceprojects/Avalonia/src/Avalonia.Base/Interactivity/RoutedEvent.cs:78-99.
2026-05-25 20:38:58 +08:00
chinboy 17baabdbe7 perf(DataGrid): reduce row group header press overhead
Gallery qualification: DataGridRowGroupHeader is created per realized row group header in grouped DataGrid views. The DataGrid.RowGroups smoke scenario realizes grouped headers during page setup, and grouped DataGrid pages create these headers during navigation or grouped data display. Setup happens when a new group header instance is created; PointerPressed runs whenever users click a group header to update current slot or toggle grouping behavior.

Correctness: DataGridRowHeader now retries owner-dependent template state from the Owner setter, preventing a null OwningGrid path when a group header template applies the row header before assigning Owner.

Avalonia basis: PointerPressed is a tunnel+bubble routed event. Event adders call AddHandler and store local routed subscriptions in Interactive._eventHandlers, while AddClassHandler subscribes once through RoutedEvent.Raised for the control type. EventRoute still honors handledEventsToo, preserving the original handled-event behavior.

Sources: .referenceprojects/Avalonia/src/Avalonia.Base/Input/InputElement.cs:158-169; .referenceprojects/Avalonia/src/Avalonia.Base/Input/InputElement.cs:380-383; .referenceprojects/Avalonia/src/Avalonia.Base/Interactivity/Interactive.cs:176-190; .referenceprojects/Avalonia/src/Avalonia.Base/Interactivity/RoutedEvent.cs:78-99; .referenceprojects/Avalonia/src/Avalonia.Base/Interactivity/EventRoute.cs:158-170.
2026-05-25 19:20:16 +08:00
chinboy e0c1dd54cc perf(DataGrid): reduce row header press handler overhead
Gallery qualification: DataGridRowHeader is the row template header slot created per realized DataGridRow. DataGrid.RowHeaders realizes 8 visible row headers in the performance smoke path, and DataGridShowCase row header, row details, and special-column examples create these headers during page navigation. Setup happens once per realized row during navigation; PointerPressed runs each time a user clicks a row header.

Avalonia basis: PointerPressed is a tunnel+bubble routed event. Event adders call AddHandler and store local routed subscriptions in Interactive._eventHandlers, while AddClassHandler subscribes once through RoutedEvent.Raised for the control type. EventRoute still honors handledEventsToo, so the row header selection path keeps the original handled-event behavior.

Sources: .referenceprojects/Avalonia/src/Avalonia.Base/Input/InputElement.cs:158-169; .referenceprojects/Avalonia/src/Avalonia.Base/Input/InputElement.cs:380-383; .referenceprojects/Avalonia/src/Avalonia.Base/Interactivity/Interactive.cs:176-190; .referenceprojects/Avalonia/src/Avalonia.Base/Interactivity/RoutedEvent.cs:78-99; .referenceprojects/Avalonia/src/Avalonia.Base/Interactivity/EventRoute.cs:158-170.
2026-05-25 18:58:13 +08:00
chinboy 4b8fd36530 perf(DataGrid): reduce group header forwarding overhead
Gallery qualification: DataGridShowCase has one Grouping table head example with 4 DataGridColumnGroupItem instances. The group headers are realized during DataGrid page navigation, and their header pointer forwarding runs when users press or release grouped headers. Although the instance count is small, this removes the remaining per-header routed subscriptions in the column header cleanup path with no visual or API change.

Avalonia basis: PointerPressed/PointerReleased event adders call AddHandler and store local routed subscriptions in Interactive._eventHandlers, while AddClassHandler subscribes once through RoutedEvent.Raised for the control type.

Sources: .referenceprojects/Avalonia/src/Avalonia.Base/Input/InputElement.cs:380-392; .referenceprojects/Avalonia/src/Avalonia.Base/Interactivity/Interactive.cs:30-42; .referenceprojects/Avalonia/src/Avalonia.Base/Interactivity/Interactive.cs:179-190; .referenceprojects/Avalonia/src/Avalonia.Base/Interactivity/RoutedEvent.cs:78-99.
2026-05-25 18:31:32 +08:00
chinboy 02bda1f152 perf(DataGrid): reduce row expander and header handler overhead
Gallery qualification: DataGridShowCase declares 65 DataGrid controls and 210 columns; column headers and row expanders are realized during page navigation, header press/release/move runs during resize/reorder/sort, and row details binding runs on row load plus expand/collapse.

Avalonia basis: Pointer event adders call AddHandler and store local subscriptions in Interactive._eventHandlers, while AddClassHandler subscribes once through RoutedEvent.Raised. GetObservable/Bind(IObservable<T>) uses direct observable binding, while BindUtils.RelayBind creates Binding + Source + Path.

Sources: .referenceprojects/Avalonia/src/Avalonia.Base/Input/InputElement.cs:353-389; .referenceprojects/Avalonia/src/Avalonia.Base/Interactivity/Interactive.cs:176-190; .referenceprojects/Avalonia/src/Avalonia.Base/Interactivity/RoutedEvent.cs:84-99; .referenceprojects/Avalonia/src/Avalonia.Base/AvaloniaObjectExtensions.cs:59-77; src/AtomUI.Core/Data/BindUtils.cs:8-36.
2026-05-25 18:19:10 +08:00
chinboy 449421de88 perf(DataGrid): reduce row details measure registration overhead
DataGridShowCase declares 65 DataGrid instances, and DataGridRowTheme creates one DataGridDetailsPresenter slot for every realized row; row presenter construction happens during page navigation, while ContentHeight changes are hit by row details measurement and expand/collapse paths.

Avalonia source: AffectsMeasure<T> is documented for static constructor registration, and its implementation subscribes an observer to property.Changed for each call.

Verified with AtomUI.Performance Release build, --verify-datagrid-states, datagrid suite count 100, and git diff --check.
2026-05-25 17:06:45 +08:00
chinboy 72774f68ad perf(DataGrid): reduce cell header state binding overhead
DataGridShowCase declares 65 DataGrid instances and 210 columns; DataGrid.GalleryShape realizes 115 data cells, so per-cell header sort/reorder state binding setup is a repeated page-load cost.

Avalonia source: Bind(IObservable<T>) routes DirectProperty bindings through DirectBindingObserver, avoiding BindUtils RelayBind path creation and per-cell captured converter delegates.

Verified with AtomUI.Performance Release build, --verify-datagrid-states, datagrid suite count 300 paired baseline/optimized runs, and git diff --check.
2026-05-25 16:52:52 +08:00
chinboy 4afb88b9d1 perf(DataGrid): tighten special column cleanup and drag indicator render
DataGridShowCase declares 65 DataGrid instances and 210 columns; special column detach applies to dynamic column rebuild/clear paths, and drag indicator render applies during column reorder interaction.

Avalonia source: Pen is a mutable AvaloniaObject with styled Brush/Thickness/DashStyle properties, and AffectsRender invalidates render on registered property changes.

Verified with AtomUI.Performance Release build, --verify-datagrid-states, datagrid suite count 100, and git diff --check.
2026-05-25 16:25:06 +08:00
chinboy 9fa8b6cb77 perf(DataGrid): reduce column header hover handler overhead
DataGridShowCase declares 65 DataGrid instances and 210 columns; realized column headers are created on every DataGrid page navigation and header hover is a normal interactive path.

Avalonia source: PointerEntered/Exited are Direct routed events, InputElement already dispatches them through class handlers to OnPointerEntered/OnPointerExited, and event property adders store local subscriptions in Interactive._eventHandlers.

Verified with AtomUI.Performance Release build, --verify-datagrid-states, datagrid suite count 100/300, and git diff --check.
2026-05-25 16:08:26 +08:00
chinboy 7653dae44f perf(DataGrid): reduce filter indicator binding overhead 2026-05-25 15:47:52 +08:00
chinboy 496ad0a6e8 perf(DataGrid): defer filter flyouts and fix header state 2026-05-25 14:57:16 +08:00
chinboy 80b3f4c347 perf(DesktopControls): reduce deferred lifecycle overhead 2026-05-25 06:40:11 +08:00
chinboy 7d38f4786d perf(Switch): reduce checked-state measure invalidations 2026-05-24 21:45:47 +08:00
chinboy 2b7fee1080 perf(ColorPicker): reduce open view binding and spectrum brush churn
ColorPickerShowCase has 23 ColorPicker/GradientColorPicker instances. The optimized path is the opened picker panel, especially repeated color spectrum, slider, palette, and gradient stop interactions within a session.

Use TemplateBinding for same-owner GradientColorPickerView template state and cache ColorSpectrum ImageBrush instances at bitmap rebuild points so HSV updates can reuse brush references.

Avalonia source references: .referenceprojects/Avalonia/src/Avalonia.Base/Data/TemplateBinding.cs:57-68, .referenceprojects/Avalonia/src/Avalonia.Base/Data/TemplateBindingExpression.cs:37-43, .referenceprojects/Avalonia/src/Avalonia.Base/Media/ImageBrush.cs:24-43.

Verification: dotnet build -c Release -f net10.0 tools/performances/AtomUI.Performance/AtomUI.Performance.csproj; dotnet run -c Release -f net10.0 --no-build --project tools/performances/AtomUI.Performance/AtomUI.Performance.csproj -- --verify-colorpicker-states; git diff --check; git diff --cached --check.
2026-05-24 19:03:35 +08:00
chinboy 08a61d1466 perf(ColorPicker): defer window deactivation subscription 2026-05-23 23:29:22 +08:00
chinboy bf73129876 perf(Splitter): reduce collapse icon and drag preview overhead 2026-05-23 09:24:49 +08:00
chinboy cbbac8cf60 perf(Breadcrumb): add baselines and fix separator propagation 2026-05-23 00:34:21 +08:00
chinboy d87d5ad501 perf(Timeline): cache indicator pens and fix pending state 2026-05-22 19:45:59 +08:00
chinboy 2e866660da perf(Statistic): refine content and timer lifecycle 2026-05-22 16:49:39 +08:00
chinboy 982bc314d4 perf(Calendar): defer inactive view cell creation 2026-05-22 13:57:24 +08:00
chinboy ff88b21876 perf(TabControl): reduce hidden tab item slot overhead 2026-05-22 13:14:29 +08:00
chinboy ee81dbb076 perf(Controls): refine Tour bindings and document Tier 1 results 2026-05-22 10:59:58 +08:00
chinboy 203707963d perf(Transfer): reduce target panel refresh overhead 2026-05-22 10:00:07 +08:00
chinboy c7e9585044 perf(TimePicker): defer closed picker presenters
Qualification: TimePickerShowCase has 15 TimePicker and 7 RangeTimePicker declarations, 22 runtime InfoPickerInput instances, and picker open/select/hover/confirm flows are realistic per-session operations across basic, confirm, interval, 12/24 hour, variants, status, and range examples.

Avalonia source refs: .referenceprojects/Avalonia/src/Avalonia.Base/Data/TemplateBindingExpression.cs:37-43 covers TemplateBinding parent PropertyChanged updates; .referenceprojects/Avalonia/src/Avalonia.Base/AvaloniaObject.cs:407-422 covers SetCurrentValue preserving value priority semantics; .referenceprojects/Avalonia/src/Avalonia.Base/Layout/Layoutable.cs:546 covers hidden measure short-circuit, and this change keeps template visuals in axaml.

Result: TimePickerShowCase cold mean 464.82ms -> 393.11ms, repeated mean 148.79ms -> 138.48ms, repeated P95 180.65ms -> 151.63ms, repeated alloc 23617.32KB -> 23430.26KB, visuals preserved at 1230.

Verification: dotnet build tools/performances/AtomUI.GalleryPerformance/AtomUI.GalleryPerformance.csproj -c Debug --framework net10.0 --no-restore; dotnet build tools/performances/AtomUI.Performance/AtomUI.Performance.csproj -c Debug --framework net10.0 --no-restore; --verify-timepicker-states; GalleryPerformance timepicker and datepicker 10 cold / 30 repeated.
2026-05-22 09:17:18 +08:00
chinboy 9f4e59d043 perf(TreeSelect): reduce SelectHandle indicator overhead 2026-05-21 23:50:48 +08:00
chinboy 3e21a87670 perf(TreeView): reduce switcher icon presenter overhead
Qualification: TreeViewShowCase has 15 TreeView declarations, 87 declared TreeViewItem nodes, and 55 runtime tree rows; page navigation, expand/collapse, search/filter, drag, and context-menu flows are realistic per-session operations.

Avalonia source refs: .referenceprojects/Avalonia/src/Avalonia.Controls/Primitives/TemplatedControl.cs:333 and :338 cover template tree creation; .referenceprojects/Avalonia/src/Avalonia.Base/Layout/Layoutable.cs:546 and :624 cover hidden measure short-circuit after creation.

Result: TreeViewShowCase cold mean 1049.62ms -> 776.51ms, repeated mean 332.44ms -> 213.41ms, repeated alloc 49964.64KB -> 33732.33KB, visuals 2108 -> 1646, IconPresenter 332 -> 112.

Verification: dotnet build src/AtomUI.Desktop.Controls/AtomUI.Desktop.Controls.csproj -c Debug --framework net10.0; dotnet build tools/performances/AtomUI.Performance/AtomUI.Performance.csproj -c Debug --framework net10.0; --verify-treeview-states; GalleryPerformance treeview 10 cold / 30 repeated.
2026-05-21 22:23:44 +08:00
chinboy 53ed62d3c1 docs(performance): add Tier 0 writeups, roadmap, and pitfalls guide 2026-05-21 15:48:52 +08:00
chinboy 18d0af516c feat: prepare release/6.0 with performance scenarios and gallery enhancements
Adds the performance harness, state-verification suites, gallery
showcases and reference docs accumulated for the 6.0 release, plus
control-level fixes:

- tools/performances/AtomUI.Performance + AtomUI.GalleryPerformance
  scaffolding with per-control scenarios and verification suites
- docs/performances/** baselines and plans
- controlgallery/** showcase data refreshes (icon gallery, range time
  pickers, multi-select cascader strategies, etc.)
- ListBox: re-apply filter on OnLoaded when FilterValue is preset
- SelectCandidateList: visible-item selection mapping under filter
- RangeDatePicker: floating popup arrow even with IsShowTime=true
2026-05-20 23:25:15 +08:00
chinboy 3c5d9e7848 fix(Window): prevent unnecessary updates on media breakpoint change 2026-05-12 11:26:33 +08:00
chinboy 702e12039f feat: implement async loading architecture for controls with debounce and timeout handling 2026-05-12 07:32:04 +08:00