Commit Graph
2550 Commits
Author SHA1 Message Date
chinboy 516cd74f7e fix: add OnDetachedFromVisualTree cleanup to multiple controls
- MotionGhostControl: unsubscribe SizeChanged and reset _layout/
  _maskCenterFrame to null, enabling correct re-initialization on
  re-attach when Content changes while detached
- GradientColorPickerTrack: clear thumbs from LogicalChildren/
  VisualChildren on detach, preventing stale thumbs on re-attach
  when GradientValue becomes null while detached
- CollapseItem: reset InAnimating flag on detach, preventing the
  control from being stuck in animating state after re-attach
- RangeInfoPickerInput: clear _topLevel reference on detach to
  prevent holding a stale TopLevel (window) reference
- TreeViewItem: clear OwnerTreeView on detach to prevent stale
  tree operations during detached period and avoid GC retention
- Card: simplify delegate instantiation style (cosmetic only)

Partially addresses issue 2.1 in docs/Issues/AtomUI_issues.md.
Remaining: AbstractBackTopFloatButtonHost, PopupConfirm,
NotificationCard, NavMenuItem, Collapse, Card token scope.
2026-04-17 17:08:55 +08:00
chinboy 6d41a4e2b3 docs: mark issue 1.4 FloatButtonGroupHost lambda as already fixed
The code was already using named methods (OnFloatButtonGroupOpenRequest/
OnFloatButtonGroupCloseRequest) with CompositeDisposable cleanup.
Update tracking doc to reflect actual state.
2026-04-17 15:50:14 +08:00
chinboy cf9a1b5a28 fix: replace lambda with named method in GroupDescription constructors to avoid closure allocation
- AbstractListGroupDescription: lambda -> OnGroupKeysCollectionChanged
- DataGridGroupDescription: lambda -> OnGroupKeysCollectionChanged
- Eliminates closure object that captures 'this', preventing potential
  self-referencing GC issue (GroupKeys.CollectionChanged holds delegate
  -> delegate captures 'this' -> 'this' owns GroupKeys)
- Update issue tracking doc: mark 1.3 as fixed (P9 done)
2026-04-17 15:48:56 +08:00
chinboy 6d655bdad8 fix(1.2+): eliminate lambda closure in WindowMessageManager.Show()
Same pattern as WindowNotificationManager fix (1e851b13):
- Add OnClose internal property to MessageCard to carry the per-message
  callback without capturing local variables from Show()
- Replace MessageClosed lambda with instance method OnMessageClosed
  (accesses _items via 'this', no local variable capture)
2026-04-17 15:14:14 +08:00
chinboy 0af89b8de6 fix(1.2): eliminate lambda closures in WindowNotificationManager.Show()
- Add OnClick/OnClose internal properties to NotificationCard to carry
  per-notification callbacks without capturing local variables
- Replace PointerPressed lambda with static OnNotificationPointerPressed
  (zero closure allocation, reads callback from card.OnClick)
- Replace NotificationClosed lambda with instance OnNotificationClosed
  (accesses _items via 'this', no local variable capture)
- Update AtomUI_issues.md: mark 1.2 as fixed, remove from P8 list
2026-04-17 15:08:39 +08:00
chinboy f5ba2e4ebe fix(1.1): remove Closed += lambda closures in MessageBox/Dialog static APIs
Modal methods (ShowMessageBoxModalAsync, ShowMessageModalAsync,
ShowDialogModalAsync x2): OpenAsync() awaits dialog close, so cleanup
is moved after await tsc.Task — no Closed subscription needed.

Non-modal methods (ShowMessageBoxAsync, ShowMessageAsync,
ShowDialogAsync x2): OpenAsync() returns after dialog is shown, so
Closed lambda is retained as the only close notification point.
The lambda is harmless: Closed fires exactly once, dialog is removed
from parent and GC'd immediately after, releasing the closure.

- Update AtomUI_issues.md: mark 1.1 as fixed, remove from P3 list
- Delete performance_memory_leak.md (tracking moved to AtomUI_issues.md)
2026-04-17 15:01:37 +08:00
chinboy ad6a346c30 fix(3.2): prevent memory leaks in DataGridCell by managing event subscriptions - dispose old subscriptions in OnApplyTemplate to avoid accumulation - release subscriptions in OnDetachedFromVisualTree 2026-04-17 13:55:01 +08:00
chinboy ac1d201d7e fix(3.3): fix event subscription leaks in ColorPicker controls - AbstractColorPicker: guard OnApplyTemplate with null check to prevent duplicate flyout subscriptions - AbstractColorPickerView: remove-before-add for ClearRequest and ColorSelected events - ColorSliderThumb: remove-before-add for SizeChanged event - ColorPickerInput: add OnDetachedFromVisualTree to unsubscribe all input events - GradientColorSlider: minor cleanup 2026-04-17 13:26:20 +08:00
chinboy 7f3ab08fd4 docs(3.3): mark ColorPicker complex state management as fixed - Update progress to 34/39 (87.2%) - Mark 3.3 ColorPicker OnApplyTemplate event subscription as fixed - ColorPickerInput, AbstractColorPickerView, ColorSliderThumb all use named handlers with remove-before-add pattern - Remove 3.3 from P2 pending list - Medium: 17/19 fixed 2026-04-17 13:24:51 +08:00
chinboy cea4bb8fa9 fix(2.1): implement IDisposable on AbstractNotifiableTransition and dispose at call sites
- INotifyTransitionCompleted interface now extends IDisposable
- AbstractNotifiableTransition<T>.Dispose() disposes Subject<bool> and nulls it
- NotifyTransitionCompleted() guards against null _subject (post-dispose)
- CompletedObservable throws ObjectDisposedException if accessed after Dispose
- AbstractMotion.RunTransitions: dispose all Transitions after await completes
  (covers both normal completion and Task.Delay timeout path)
- AbstractMotion.ConfigureTransitions: dispose existing Transitions before Clear
  to prevent Subject leaks when transitions are rebuilt
- Update performance_memory_leak.md: 32/39 fixed (82.1%), High 8/8 all done
2026-04-17 13:04:41 +08:00
chinboy bd1b270c81 revert(3.4): Form Items.CollectionChanged lambda is a false positive — no fix needed
Items is an internal ItemCollection owned by Form with identical lifetime.
The subscription cannot leak across lifetimes: when Form is GC'd, Items and
its event subscriptions are collected with it. Mark 3.4 as false positive in docs.
2026-04-17 12:56:24 +08:00
chinboy fae2788bc5 fix(3.4): extract Form Items.CollectionChanged lambda to named method HandleItemsCollectionChanged
- Replace anonymous lambda with named method to allow precise -=  unsubscription
- Prevents subscription leak when Items is replaced by an external CollectionView
- Update performance_memory_leak.md: 32/39 fixed (82.1%), Medium 16/19
2026-04-17 12:54:33 +08:00
chinboy ca1c990e7b fix(1.2): replace anonymous lambda with WeakReference forwarder in DataGridCollectionView to eliminate CollectionChanged memory leak
- Mirror the same WeakCollectionChangedForwarder pattern applied to ListCollectionView (29452afe)
- Add IDisposable to DataGridCollectionView class declaration
- Add _collectionChangedForwarder field (WeakCollectionChangedForwarder?)
- Replace anonymous lambda subscription with forwarder in constructor
- Add Dispose() for eager cleanup
- Add WeakCollectionChangedForwarder nested class with self-unsubscribe on GC
- All Critical (P0) issues now fully resolved
- Update performance_memory_leak.md: 31/39 fixed (79.5%), Critical 7/7
2026-04-17 12:48:57 +08:00
chinboy a896c7833e docs(1.1): annotate section title with fix status and commit hash 2026-04-17 12:46:14 +08:00
chinboy ea59ecac29 docs(1.1): fill in commit hash 29452afe and update critical/total fix counts 2026-04-17 12:43:05 +08:00
chinboy 652398a207 fix(1.1): replace anonymous lambda with WeakReference forwarder in ListCollectionView to eliminate CollectionChanged memory leak
- Add WeakCollectionChangedForwarder nested class: source holds strong ref to
  forwarder, forwarder holds WeakReference<ListCollectionView> — prevents the
  source collection from rooting the view
- Self-unsubscribes on next event after view is GC'd; no lingering delegate
- Keep IDisposable.Dispose() for eager cleanup when ItemsSource changes in ListView
- ListView: track _ownsCollectionView flag and call Dispose() on old view only
  when we created it (not user-provided IListCollectionView)
- Remove OnDetachedFromVisualTree disposal to avoid breaking reattach scenarios
  (tab switching, panel rebuilds, etc.) — WeakReference handles lifetime safely
- Update performance_memory_leak.md: mark 1.1 as fixed, progress 30/39 (76.9%)
2026-04-17 12:40:09 +08:00
chinboy 9ec5bc9fa7 fix(Statistic): remove dead code in GenerateRemainingTimeText and use smart default time format 2026-04-17 10:48:35 +08:00
chinboy 87e9a8b572 perf(Tag): replace static Dictionary with FrozenDictionary for PresetColorMap, StatusColorMap and PresetPalettes 2026-04-17 10:41:57 +08:00
chinboy 8c6498b6c3 refactor(Notification): split PollingInterval into CardExpiredPollingInterval and CleanupPollingInterval for independent tuning 2026-04-17 10:31:14 +08:00
chinboy 4d94e60cfc perf(Notification): reduce polling to 200ms, add PollingInterval property, and use HashSet for O(1) cleanup queue dedup 2026-04-17 10:13:16 +08:00
chinboy b18d82e56a docs(MemoryLeak): mark 5.18 as fixed, update progress to 14/39 (35.9%) 2026-04-17 10:06:04 +08:00
chinboy 291a91ada4 perf(Watermark): cache rotation matrices to eliminate per-tile per-frame trig allocations 2026-04-17 10:05:27 +08:00
chinboy 4efb3ed55f docs(MemoryLeak): add performance and memory leak analysis guidelines for AtomUI 2026-04-17 10:02:05 +08:00
chinboy 17575bcfa6 docs(MemoryLeak): mark 5.17 as fixed, update progress to 13/39 (33.3%) 2026-04-17 10:00:04 +08:00
chinboy ae1a6cfda1 fix(ToolTip): call StopTimer before creating new timer and replace lambda with named handler in StartShowTimer 2026-04-17 09:59:35 +08:00
chinboy c48de5f137 docs(MemoryLeak): mark 5.15 and 5.16 as fixed, update progress to 12/39 (30.8%) 2026-04-17 09:58:24 +08:00
chinboy 24d6e170ac fix(Space): use remove-before-add for Children.PropertyChanged to prevent duplicate subscription 2026-04-17 09:54:56 +08:00
chinboy 3204c7a87f fix(FloatButton): replace lambda subscriptions with named handlers in FloatButtonGroupHost to prevent memory leak 2026-04-17 09:51:14 +08:00
chinboy a5ecee5927 fix(5.13): properly clean up old DispatcherTimer in Mentions and AutoComplete
- Always stop, unsubscribe, and null out old _delayTimer before creating new instance
- Prevents event handler accumulation when MinimumPopulateDelay changes
- Unify handling between Mentions and AbstractAutoComplete
- Fixes issue where timer event handlers would accumulate on rapid property changes
2026-04-17 07:58:02 +08:00
chinboy 39064b8bcb fix(5.12): add Dispose call for CancellationTokenSource in AbstractSkeleton
- StartActiveAnimation: dispose old CTS before creating new instance
- StopActiveAnimation: dispose CTS and set to null
- BuildActiveAnimation: dispose CTS before rebuilding animation
- Prevents WaitHandle and unmanaged resources from leaking during repeated animation start/stop cycles
2026-04-17 07:21:05 +08:00
chinboy 2117910517 docs(5.11): update fix status and refactor ColorPicker async methods for clarity
- Mark issue 5.11 (async void methods) as fully fixed (4/4)
- Remove backward compatibility wrapper methods, call async versions directly
- Add Avalonia.VisualTree import to ColorSlider and SelectableTextBlock
- Improve code indentation and readability in ColorSpectrum.CreateBitmapsAndColorMapAsync
- Clean up ColorSpectrum property default values in property definitions
- Update documentation with unified fix pattern for all 4 async void methods
- Remove obsolete void wrapper methods (Copy, UpdateBackground, CopyToClipboard)
2026-04-16 22:58:42 +08:00
chinboy 32b0d9c5f4 fix(5.11): add exception handling to async void methods in ColorPicker and DataGrid
- ColorSpectrum: convert CreateBitmapsAndColorMap to async Task with try-catch
- ColorSlider: convert UpdateBackground to async Task with IsAttachedToVisualTree check
- DataGrid: convert CopyToClipboard to async Task with exception handling
- SelectableTextBlock: convert Copy to async Task with IsAttachedToVisualTree check
- Keep original void methods for backward compatibility (fire-and-forget pattern)
- Add graceful exception handling to prevent app crashes
- Verify control is attached before updating UI after async operations
2026-04-16 22:57:30 +08:00
chinboy a8847c7107 docs(5.10): update fix status for TreeView/CascaderView async load CancellationTokenSource
- Mark 5.10 as fixed with commit 7472c56a
- Document complete lifecycle management implementation
- Add AsyncLoadTimeout property details
- Update fix progress: 10 issues fixed (25.6%)
2026-04-16 21:44:45 +08:00
chinboy 7fa447073f fix(5.10): complete async load CancellationTokenSource lifecycle management
- Add _loadingTokens list to track all pending CTS instances
- Add CTS to list when async load starts
- Remove CTS from list and dispose in finally block
- Add cleanup logic in OnDetachedFromVisualTree to cancel and dispose all pending CTS
- Ensures all async operations are properly cleaned up when control is detached
- Prevents resource leaks and ensures no callbacks on detached controls
- Applied to both TreeView and CascaderView
2026-04-16 21:33:56 +08:00
chinboy 4086b3536e feat(5.10): make async load timeout configurable via AsyncLoadTimeout property
- Add AsyncLoadTimeout property to TreeView (default: 30 seconds)
- Add AsyncLoadTimeout property to CascaderView (default: 30 seconds)
- Replace hardcoded timeout values with property values
- Allows users to customize timeout duration in XAML or code
- Maintains backward compatibility with default 30-second timeout
2026-04-16 18:38:54 +08:00
chinboy 4e2dd770d7 fix(5.9): move glyph PropertyChanged subscription to lifecycle hooks in Watermark
- Move PropertyChanged subscription from constructor to OnAttachedToVisualTree
- Add PropertyChanged unsubscription in OnDetachedFromVisualTree
- Ensure proper lifecycle management when Watermark is reattached to visual tree
- Prevent memory leaks from glyph event handlers

Also update performance_memory_leak.md:
- Mark 5.9 (Watermark glyph.PropertyChanged lambda) as fixed
- Add fix timestamp and implementation details
2026-04-16 18:01:03 +08:00
chinboy 230b8a44ba fix(5.6): replace lambda with named method in ToolTipService timer handler
- Replace anonymous lambda with named method HandleShowTimerTick()
- Call StopTimer() at the beginning of StartShowTimer() to clean up old timer
- Use ValueTuple to safely extract control reference from timer Tag
- Prevent multiple parallel timers when mouse moves quickly

Also update performance_memory_leak.md:
- Mark 5.6 (ToolTip service global event subscription) as fixed
- Add fix timestamp and implementation details
2026-04-16 17:53:18 +08:00
chinboy 8c1f2cd073 fix(5.4): add Dispose call for CancellationTokenSource in MarqueeLabel
- Add Dispose() call in HandleCleanupMarqueeAnimation() to release unmanaged resources
- Set CancellationTokenSource to null after disposal
- Ensure complete lifecycle management of CancellationTokenSource

Also update performance_memory_leak.md:
- Mark 5.4 (MarqueeLabel animation cleanup) as fixed
- Add fix timestamp and implementation details
2026-04-16 17:38:56 +08:00
chinboy 272d480bff fix(3.7): replace delegate fields with private methods in ColorPickerInput
- Remove 8 private event handler delegate fields (_alphaInputValueChangedHandler, etc.)
- Add 8 private methods to replace delegate fields (HandleAlphaInputValueChanged, etc.)
- Update OnApplyTemplate to use method references instead of delegate fields
- Avoid allocating new delegate objects on each OnApplyTemplate call
- Improve code clarity by using private methods for lambdas that don't capture closure variables

Also update performance_memory_leak.md:
- Mark 5.3 (CompositeDisposable) as fixed
- Update 3.7 fix description to reflect the actual implementation using private methods
- Add fix timestamp and details
2026-04-16 17:32:05 +08:00
chinboy a2e352283d fix(5.2): replace lambda with named methods in FlyoutStateHelper timer handlers 2026-04-16 16:08:30 +08:00
chinboy f9f3363dab fix(5.1): move Segmented SelectionChanged subscription from constructor to lifecycle hooks
Move SelectionChanged event subscription from constructor to lifecycle hooks:
- Remove subscription from constructor
- Add subscription in OnAttachedToVisualTree()
- Add unsubscription in OnDetachedFromVisualTree()
This ensures proper cleanup when the control is detached from the visual tree,
following best practices for event management and preventing potential reference cycles.
File: src/AtomUI.Controls/Segmented/AbstractSegmented.cs
- Removed: SelectionChanged subscription from constructor
- Added: OnAttachedToVisualTree() override with subscription
- Added: OnDetachedFromVisualTree() override with unsubscription
Fixes issue 5.1 from performance_memory_leak.md analysis.
2026-04-16 16:01:29 +08:00
chinboy 0995ca48a7 docs: mark section 3.7 ColorPickerInput as fixed
Update documentation to mark section 3.7 (ColorPickerInput OnApplyTemplate Lambda stacking)
as fixed. Investigation shows the code already implements the correct event management pattern:
Implementation details:
- Event handlers stored in class-level fields (lines 80-87)
- All old subscriptions removed at OnApplyTemplate start (lines 127-160)
- New named lambda handlers created and subscribed (lines 179-289)
- Prevents event handler accumulation on template reapplication
Update statistics:
- Fixed issues: 2 → 3
- Progress: 5.1% → 7.7% (3/39)
- Critical problems: 0 → 1 fixed
Update fix log to include 3.7 alongside 4.5 and 4.8 fixes.
2026-04-16 15:58:01 +08:00
chinboy e9d3e85194 docs: update performance_memory_leak.md with fix status for 4.5 and 4.8
Update documentation status:
- Mark section 4.5 (OptionButtonGroup Lambda events) as FIXED
  - Commit: 01ec42d6
  - Details: Convert lambda to named method, subscribe in constructor, unsubscribe in OnDetachedFromVisualTree
- Mark section 4.8 (Async methods CancellationToken support) as FIXED
  - Commits: 76aadb94, 4c9054dd
  - Details: Add CancellationToken support to 7 files (Upload, MessageBox, Popup, MenuItem, FileUploadScheduler, IFileUploadScheduler, IconPackageGenerator)
  - Code changes: +35, -21
Add:
- Modification progress summary at the top (5.1% complete - 2/39 issues fixed)
- Update priority table with fix status
- Update issue statistics with fix counts
- Add detailed fix log at the end with commit hashes and implementation details
Documentation updates: +140, -47
2026-04-16 15:55:56 +08:00
chinboy 92fb2a3581 fix(4.8): add CancellationToken support to async methods
This commit adds proper cancellation support to multiple async methods:
- MessageBox.OpenAsync() - now accepts CancellationToken parameter
- Popup.MotionAwareOpenAsync/CloseAsync() - support WaitAsync with CancellationToken
- MenuItem.CloseItemAsync() - propagates CancellationToken recursively
- FileUploadScheduler - CancelAllAsync/SetMaxConcurrentTasksAsync/SetTransportAsync
- IconPackageGenerator.GenerateAsync() - add cancellation points
Also updated IFileUploadScheduler interface to match implementation signatures.
Benefits:
- Allows graceful cancellation of long-running operations
- Prevents hanging operations when controls are destroyed
- Enables proper cleanup when user navigates away
- Supports timeout patterns via CancellationTokenSource
Fixes section 4.8 of performance_memory_leak.md analysis.
2026-04-16 15:53:14 +08:00
chinboy 8ac95d4cba fix(Upload): add CancellationToken support and lifecycle management
- Add CancellationToken parameter to ResetAsync() for cancellable operations
- Add OnAttachedToVisualTree to create CancellationTokenSource when control is attached
- Update OnDetachedFromVisualTree to cancel and dispose CancellationTokenSource when control is detached
- Add cancellation checks in CancelAllUploadTaskAsync() to respect cancellation requests
Fixes issue #4.8: async methods now support proper cancellation, allowing clean shutdown of pending upload operations when the control is destroyed or navigation occurs.
2026-04-16 15:41:39 +08:00
chinboy 8a5b7aac73 feat(Dialog,Upload): add CancellationToken support to async methods 2026-04-16 15:27:31 +08:00
chinboy f4df590d18 fix(WindowNotificationManager): unsubscribe timer Tick events in Dispose and remove over-optimized card handler tracking 2026-04-16 15:15:17 +08:00
chinboy 90a0c6806d fix(MemoryLeak): add cache size limit to IconProviderCache and fix OptionButtonGroup event subscription lifecycle 2026-04-16 14:53:34 +08:00
chinboy 15f4ed015a fix(OptionButtonGroup): subscribe to ChildIndexChanged in constructor instead of OnAttachedToVisualTree
Fixes the issue where the event handler was being subscribed multiple times when the control was re-attached to the visual tree. By moving the subscription to the constructor (where it happens only once) and the unsubscription to OnDetachedFromVisualTree, we ensure the handler is properly managed throughout the control's lifetime.
2026-04-16 14:41:44 +08:00
chinboy 3a57fadf83 fix(Tour): clean up event subscriptions in OnDetachedFromVisualTree 2026-04-16 14:28:14 +08:00