Commit Graph
2196 Commits
Author SHA1 Message Date
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 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 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 291a91ada4 perf(Watermark): cache rotation matrices to eliminate per-tile per-frame trig allocations 2026-04-17 10:05:27 +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 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 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 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
chinboy 0195b16ba7 fix: Drawer Close() 方法移除 _container = null
移除 Close() 方法中的 _container = null 赋值,允许容器在再次打开时被复用,
避免 'control already has a visual parent' 错误。
2026-04-16 14:14:19 +08:00
chinboy a8293a1e8f fix: Drawer 在 OnDetachedFromVisualTree 中设置 disposables 为 null
在 Dispose 后将 _containerDisposables 和 _relayBindingDisposables 设置为 null,避免重复 Dispose 和潜在的内存泄漏。
2026-04-16 14:07:16 +08:00
chinboy 2e2e69cb88 fix: Carousel 自动播放定时器泄漏
在 BuildAutoPlayTimer 中创建新定时器时未先清理旧的,导致旧定时器继续运行。

修复方案:
- 在创建新定时器前先停止旧定时器
- 取消旧定时器的 Tick 事件订阅
- 在禁用自动播放时也进行同样的清理

这样避免多个定时器同时运行导致的 CPU 浪费和内存泄漏。
2026-04-16 13:38:03 +08:00
chinboy 3f5e5fd656 fix: ColorPickerInput OnApplyTemplate 8个 lambda 事件叠加
在 OnApplyTemplate 中对 8 个输入控件的 ValueChanged/TextChanged 事件使用匿名 lambda 订阅,每次模板重新应用都会叠加新的订阅。

修复方案:
- 添加 8 个字段存储事件处理器
- 在 OnApplyTemplate 开头先移除旧订阅
- 将匿名 lambda 改为存储在字段中的委托

这样每次模板重新应用时,旧订阅会被正确移除,新订阅才会添加,避免叠加。
2026-04-16 13:33:34 +08:00
chinboy 187547f9db fix: InfoPickerInput OnApplyTemplate lambda 事件叠加
在 OnApplyTemplate 中对 DecoratedBox.TemplateApplied、DecoratedBox.PropertyChanged、PickerClearUpButton.ClearRequest 事件使用匿名 lambda 订阅,每次模板重新应用都会叠加新的订阅。

修复方案:
- 添加字段存储事件处理器:_decoratedBoxTemplateAppliedHandler、_decoratedBoxPropertyChangedHandler、_clearRequestHandler
- 在 OnApplyTemplate 开头先移除旧订阅
- 将匿名 lambda 改为存储在字段中的委托

这样每次模板重新应用时,旧订阅会被正确移除,新订阅才会添加,避免叠加。
2026-04-16 13:25:46 +08:00
chinboy 6a435bc2be fix: InfoPickerInput OnApplyTemplate lambda 事件叠加 — 改为命名方法并在开头移除旧订阅
- 问题:OnApplyTemplate 中使用匿名 lambda 订阅 DecoratedBox.TemplateApplied、DecoratedBox.PropertyChanged、PickerClearUpButton.ClearRequest 事件
- 每次模板重新应用(主题切换等)都会叠加新的订阅,导致回调数量线性增长
- 影响:所有派生自 InfoPickerInput 的控件(DatePicker、TimePicker 等)

修复方案:
1. 添加字段存储事件处理器引用:_decoratedBoxTemplateAppliedHandler、_decoratedBoxPropertyChangedHandler、_clearRequestHandler
2. 在 OnApplyTemplate 开头先移除旧订阅
3. 将匿名 lambda 改为存储在字段中的委托,确保可以取消订阅

这样每次模板重新应用时,旧订阅会被正确移除,新订阅才会添加,避免叠加。
2026-04-16 13:16:05 +08:00
chinboy f92ab2615d fix: TimerStatistic 定时器泄漏 — 旧定时器未停止/释放
修复 #3.3: BuildTimer() 创建新 DispatcherTimer 时未停止旧定时器,
导致多个定时器并行运行。OnDetachedFromVisualTree 中也未清理定时器。
2026-04-16 13:07:54 +08:00
chinboy c83d294589 fix: SwitchKnob OnDetachedFromVisualTree 调用错误的基类方法
修复 #3.2: OnDetachedFromVisualTree 中调用了 base.OnAttachedToVisualTree(e)
而非 base.OnDetachedFromVisualTree(e),导致基类清理逻辑失效。
2026-04-16 13:04:35 +08:00
chinboy 66aac27789 fix: TransformTrackingHelper DetachedFromVisualTree 事件订阅运算符错误 (-= → +=)
修复 #3.1: SetVisual() 中 DetachedFromVisualTree 使用了 -= 而非 +=,
导致 OnDetachedFromVisualTree 永远不会触发,父级 Visual 链的
PropertyChanged 订阅永久泄漏。
2026-04-16 13:00:44 +08:00
chinboy efa11d630c docs: update documentation and package examples for version 5.2.0-build.4 2026-04-16 10:30:43 +08:00
chinboy 0f63231ea2 refactor: Complete API audit refinements - 14/18 issues resolved
Comprehensive API naming and design consistency improvements:
HIGH SEVERITY (4/4 - 100%): Abstract keyword, spelling fixes, bool naming
MEDIUM SEVERITY (8/8 - 100%): Property naming, event patterns, type alignment
LOW SEVERITY (2/6 - 33%): Enum values, redundant prefixes
Updates:
- Fixed 14 API design issues across multiple controls
- Updated documentation and examples
- All changes compile successfully
Progress: 14/18 (77.8%)
2026-04-16 07:34:14 +08:00
chinboy 7b4f0d3988 fix(Alert,Tag,CountBadge): fix high-severity API naming issues - 4/4 completed
Fixed three critical bool property naming problems to align with project conventions:
1. Alert.IsMessageMarqueEnabled → IsMessageMarqueeEnabled
   - Fixed spelling error (missing final 'e' in 'Marquee')
   - Updated: Alert.cs, AlertTheme.axaml, gallery examples, docs
2. Tag.Bordered → IsBordered
   - Aligned bool property with 'Is' prefix convention (60+ other bool properties follow this pattern)
   - Updated: AbstractTag.cs, SelectTagTheme.axaml, gallery examples, docs
3. CountBadge.ShowZero → IsShowZero
   - Aligned bool property with IsShow* pattern (IsShowIcon, IsShowArrow, etc.)
   - Updated: AbstractCountBadge.cs, gallery examples, docs
All changes compile successfully. Progress: 4/18 (22.2%) high-severity issues resolved.
Updated API-Audit-Report.md with completion status and detailed change list.
2026-04-15 23:41:59 +08:00