From 77258c6ca90e1a2c44df349fe2700a1fc26c8198 Mon Sep 17 00:00:00 2001 From: qinware Date: Fri, 5 Sep 2025 16:06:46 +0800 Subject: [PATCH] Refactor SwitchKnob bindings --- .../PaletteColorItem.cs | 21 ++++---- src/AtomUI.Controls/Buttons/SplitButton.cs | 51 +++++++++---------- src/AtomUI.Controls/Input/SearchEdit.cs | 30 ++++------- src/AtomUI.Controls/NavMenu/NavMenu.cs | 25 ++++----- .../Pagination/PaginationNavItem.cs | 26 ++++------ src/AtomUI.Controls/Popup/Popup.cs | 15 +++--- .../RadioButton/RadioIndicator.cs | 35 +++++-------- src/AtomUI.Controls/Switch/SwitchKnob.cs | 13 +++-- .../TextBlock/SelectableTextBlock.cs | 19 +++++-- 9 files changed, 103 insertions(+), 132 deletions(-) diff --git a/src/AtomUI.Controls.ColorPicker/PaletteColorItem.cs b/src/AtomUI.Controls.ColorPicker/PaletteColorItem.cs index 5f5409d94..bf39a5a1b 100644 --- a/src/AtomUI.Controls.ColorPicker/PaletteColorItem.cs +++ b/src/AtomUI.Controls.ColorPicker/PaletteColorItem.cs @@ -1,9 +1,7 @@ -using System.Reactive.Disposables; using AtomUI.Animations; using AtomUI.Controls.Themes; using AtomUI.Controls.Utils; using AtomUI.IconPkg; -using AtomUI.Theme; using AtomUI.Theme.Data; using AtomUI.Theme.Styling; using Avalonia; @@ -13,14 +11,13 @@ using Avalonia.Controls; using Avalonia.Controls.Primitives; using Avalonia.Data; using Avalonia.Interactivity; -using Avalonia.LogicalTree; using Avalonia.Media; namespace AtomUI.Controls; using AvaloniaRadioButton = Avalonia.Controls.RadioButton; -internal class PaletteColorItem : AvaloniaRadioButton, IResourceBindingManager +internal class PaletteColorItem : AvaloniaRadioButton { #region 公共属性定义 @@ -61,8 +58,8 @@ internal class PaletteColorItem : AvaloniaRadioButton, IResourceBindingManager } #endregion - CompositeDisposable? IResourceBindingManager.ResourceBindingsDisposable { get; set; } private Icon? _checkedMark; + private IDisposable? _borderThicknessDisposable; static PaletteColorItem() { @@ -92,19 +89,19 @@ internal class PaletteColorItem : AvaloniaRadioButton, IResourceBindingManager } } - protected override void OnAttachedToLogicalTree(LogicalTreeAttachmentEventArgs e) + protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e) { - base.OnAttachedToLogicalTree(e); - this.AddResourceBindingDisposable(TokenResourceBinder.CreateTokenBinding(this, BorderThicknessProperty, + base.OnAttachedToVisualTree(e); + _borderThicknessDisposable = TokenResourceBinder.CreateTokenBinding(this, BorderThicknessProperty, SharedTokenKey.BorderThickness, BindingPriority.Template, - new RenderScaleAwareThicknessConfigure(this))); + new RenderScaleAwareThicknessConfigure(this)); } - protected override void OnDetachedFromLogicalTree(LogicalTreeAttachmentEventArgs e) + protected override void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e) { - base.OnDetachedFromLogicalTree(e); - this.DisposeTokenBindings(); + base.OnDetachedFromVisualTree(e); + _borderThicknessDisposable?.Dispose(); } protected override void OnApplyTemplate(TemplateAppliedEventArgs e) diff --git a/src/AtomUI.Controls/Buttons/SplitButton.cs b/src/AtomUI.Controls/Buttons/SplitButton.cs index 7d2926a96..ac988d703 100644 --- a/src/AtomUI.Controls/Buttons/SplitButton.cs +++ b/src/AtomUI.Controls/Buttons/SplitButton.cs @@ -31,8 +31,7 @@ public class SplitButton : ContentControl, ICommandSource, ISizeTypeAware, IControlSharedTokenResourcesHost, - IWaveSpiritAwareControl, - IResourceBindingManager + IWaveSpiritAwareControl { #region 公共属性定义 @@ -274,7 +273,6 @@ public class SplitButton : ContentControl, Control IMotionAwareControl.PropertyBindTarget => this; Control IControlSharedTokenResourcesHost.HostControl => this; string IControlSharedTokenResourcesHost.TokenId => ButtonToken.ID; - CompositeDisposable? IResourceBindingManager.ResourceBindingsDisposable { get; set; } #endregion @@ -289,6 +287,7 @@ public class SplitButton : ContentControl, private CompositeDisposable? _flyoutBindingDisposables; private CompositeDisposable? _flyoutHelperBindingDisposables; + private IDisposable? _borderThicknessDisposable; static SplitButton() { @@ -312,8 +311,7 @@ public class SplitButton : ContentControl, { CanExecuteChanged(sender, e); } - - /// + private void CanExecuteChanged(object? sender, EventArgs e) { var (command, parameter) = (Command, CommandParameter); @@ -424,22 +422,6 @@ public class SplitButton : ContentControl, _primaryButton.Click -= HandlePrimaryButtonClick; } } - - protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e) - { - base.OnAttachedToVisualTree(e); - _flyoutStateHelper.NotifyAttachedToVisualTree(); - UpdatePseudoClasses(); - RegisterFlyoutEvents(Flyout); - SetupDefaultFlyoutButtonIcon(); - } - - protected override void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e) - { - base.OnDetachedFromVisualTree(e); - UnregisterFlyoutEvents(Flyout); - _flyoutStateHelper.NotifyDetachedFromVisualTree(); - } private void SetupDefaultFlyoutButtonIcon() { @@ -465,6 +447,27 @@ public class SplitButton : ContentControl, _primaryButton.Click += HandlePrimaryButtonClick; } } + + protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e) + { + base.OnAttachedToVisualTree(e); + _borderThicknessDisposable = TokenResourceBinder.CreateTokenBinding(this, BorderThicknessProperty, + SharedTokenKey.BorderThickness, + BindingPriority.Template, + new RenderScaleAwareThicknessConfigure(this)); + _flyoutStateHelper.NotifyAttachedToVisualTree(); + UpdatePseudoClasses(); + RegisterFlyoutEvents(Flyout); + SetupDefaultFlyoutButtonIcon(); + } + + protected override void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e) + { + base.OnDetachedFromVisualTree(e); + UnregisterFlyoutEvents(Flyout); + _flyoutStateHelper.NotifyDetachedFromVisualTree(); + _borderThicknessDisposable?.Dispose(); + } protected override void OnAttachedToLogicalTree(LogicalTreeAttachmentEventArgs e) { @@ -487,11 +490,6 @@ public class SplitButton : ContentControl, _flyoutHelperBindingDisposables.Add(BindUtils.RelayBind(this, MouseLeaveDelayProperty, _flyoutStateHelper, FlyoutStateHelper.MouseLeaveDelayProperty)); _flyoutHelperBindingDisposables.Add(BindUtils.RelayBind(this, TriggerTypeProperty, _flyoutStateHelper, FlyoutStateHelper.TriggerTypeProperty)); - - this.AddResourceBindingDisposable(TokenResourceBinder.CreateTokenBinding(this, Border.BorderThicknessProperty, - SharedTokenKey.BorderThickness, - BindingPriority.Template, - new RenderScaleAwareThicknessConfigure(this))); } protected override void OnDetachedFromLogicalTree(LogicalTreeAttachmentEventArgs e) @@ -507,7 +505,6 @@ public class SplitButton : ContentControl, Command.CanExecuteChanged -= CanExecuteChanged; } _flyoutHelperBindingDisposables?.Dispose(); - this.DisposeTokenBindings(); } protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs e) diff --git a/src/AtomUI.Controls/Input/SearchEdit.cs b/src/AtomUI.Controls/Input/SearchEdit.cs index d8a7bac19..1ec849251 100644 --- a/src/AtomUI.Controls/Input/SearchEdit.cs +++ b/src/AtomUI.Controls/Input/SearchEdit.cs @@ -1,6 +1,4 @@ -using System.Reactive.Disposables; -using AtomUI.Controls.Themes; -using AtomUI.Theme; +using AtomUI.Controls.Themes; using AtomUI.Theme.Data; using AtomUI.Theme.Styling; using Avalonia; @@ -8,7 +6,6 @@ using Avalonia.Controls; using Avalonia.Controls.Primitives; using Avalonia.Data; using Avalonia.Interactivity; -using Avalonia.LogicalTree; namespace AtomUI.Controls; @@ -18,7 +15,7 @@ public enum SearchEditButtonStyle Primary } -public class SearchEdit : LineEdit, IResourceBindingManager +public class SearchEdit : LineEdit { #region 公共属性定义 @@ -41,13 +38,6 @@ public class SearchEdit : LineEdit, IResourceBindingManager } #endregion - - - #region 内部属性定义 - - CompositeDisposable? IResourceBindingManager.ResourceBindingsDisposable { get; set; } - - #endregion #region 公共事件定义 @@ -61,20 +51,22 @@ public class SearchEdit : LineEdit, IResourceBindingManager } #endregion + + private IDisposable? _borderThicknessDisposable; - protected override void OnAttachedToLogicalTree(LogicalTreeAttachmentEventArgs e) + protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e) { - base.OnAttachedToLogicalTree(e); - this.AddResourceBindingDisposable(TokenResourceBinder.CreateTokenBinding(this, BorderThicknessProperty, + base.OnAttachedToVisualTree(e); + _borderThicknessDisposable = TokenResourceBinder.CreateTokenBinding(this, BorderThicknessProperty, SharedTokenKey.BorderThickness, BindingPriority.Template, - new RenderScaleAwareThicknessConfigure(this))); + new RenderScaleAwareThicknessConfigure(this)); } - protected override void OnDetachedFromLogicalTree(LogicalTreeAttachmentEventArgs e) + protected override void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e) { - base.OnDetachedFromLogicalTree(e); - this.DisposeTokenBindings(); + base.OnDetachedFromVisualTree(e); + _borderThicknessDisposable?.Dispose(); } protected override void OnApplyTemplate(TemplateAppliedEventArgs e) diff --git a/src/AtomUI.Controls/NavMenu/NavMenu.cs b/src/AtomUI.Controls/NavMenu/NavMenu.cs index 5450d047a..34bd1e4e2 100644 --- a/src/AtomUI.Controls/NavMenu/NavMenu.cs +++ b/src/AtomUI.Controls/NavMenu/NavMenu.cs @@ -2,7 +2,6 @@ using System.Reactive.Disposables; using AtomUI.Controls.Themes; using AtomUI.Data; -using AtomUI.Theme; using AtomUI.Theme.Data; using AtomUI.Theme.Styling; using Avalonia; @@ -40,7 +39,7 @@ public class NavMenuItemClickEventArgs : RoutedEventArgs NavMenuPseudoClass.VerticalMode, NavMenuPseudoClass.DarkStyle, NavMenuPseudoClass.LightStyle)] -public class NavMenu : NavMenuBase, IResourceBindingManager +public class NavMenu : NavMenuBase { #region 公共属性定义 @@ -108,15 +107,14 @@ public class NavMenu : NavMenuBase, IResourceBindingManager get => GetValue(HorizontalBorderThicknessProperty); set => SetValue(HorizontalBorderThicknessProperty, value); } - - CompositeDisposable? IResourceBindingManager.ResourceBindingsDisposable { get; set; } - + #endregion private static readonly FuncTemplate DefaultPanel = new(() => new StackPanel { Orientation = Orientation.Vertical }); private ItemsPresenter? _menuItemsPresenter; private readonly Dictionary _itemsBindingDisposables = new(); + private IDisposable? _borderThicknessDisposable; static NavMenu() { @@ -296,28 +294,23 @@ public class NavMenu : NavMenuBase, IResourceBindingManager protected override void OnAttachedToLogicalTree(LogicalTreeAttachmentEventArgs e) { base.OnAttachedToLogicalTree(e); - this.AddResourceBindingDisposable(TokenResourceBinder.CreateTokenBinding(this, HorizontalBorderThicknessProperty, - SharedTokenKey.LineWidth, - BindingPriority.Template, - new RenderScaleAwareDoubleConfigure(this))); SetupInteractionHandler(); } - - protected override void OnDetachedFromLogicalTree(LogicalTreeAttachmentEventArgs e) - { - base.OnDetachedFromLogicalTree(e); - this.DisposeTokenBindings(); - } - + protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e) { base.OnAttachedToVisualTree(e); + _borderThicknessDisposable = TokenResourceBinder.CreateTokenBinding(this, HorizontalBorderThicknessProperty, + SharedTokenKey.LineWidth, + BindingPriority.Template, + new RenderScaleAwareDoubleConfigure(this)); InteractionHandler?.Attach(this); } protected override void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e) { base.OnDetachedFromVisualTree(e); + _borderThicknessDisposable?.Dispose(); InteractionHandler?.Detach(this); } diff --git a/src/AtomUI.Controls/Pagination/PaginationNavItem.cs b/src/AtomUI.Controls/Pagination/PaginationNavItem.cs index 8fd3cd633..fb3ee586b 100644 --- a/src/AtomUI.Controls/Pagination/PaginationNavItem.cs +++ b/src/AtomUI.Controls/Pagination/PaginationNavItem.cs @@ -1,8 +1,6 @@ -using System.Reactive.Disposables; using AtomUI.Animations; using AtomUI.Controls.Utils; using AtomUI.IconPkg; -using AtomUI.Theme; using AtomUI.Theme.Data; using AtomUI.Theme.Styling; using Avalonia; @@ -12,7 +10,6 @@ using Avalonia.Controls.Primitives; using Avalonia.Data; using Avalonia.Input; using Avalonia.Interactivity; -using Avalonia.LogicalTree; using Avalonia.VisualTree; namespace AtomUI.Controls; @@ -25,9 +22,7 @@ internal enum PaginationItemType Ellipses } -internal class PaginationNavItem : ContentControl, - ISelectable, - IResourceBindingManager +internal class PaginationNavItem : ContentControl, ISelectable { public static readonly StyledProperty IsSelectedProperty = SelectingItemsControl.IsSelectedProperty.AddOwner(); @@ -93,9 +88,8 @@ internal class PaginationNavItem : ContentControl, private set => SetAndRaise(IsPressedProperty, ref _isPressed, value); } - CompositeDisposable? IResourceBindingManager.ResourceBindingsDisposable { get; set; } - internal int PageNumber { get; set; } = -1; + private IDisposable? _borderThicknessDisposable; static PaginationNavItem() { @@ -106,19 +100,19 @@ internal class PaginationNavItem : ContentControl, AffectsRender(BackgroundProperty, BorderBrushProperty); } - protected override void OnAttachedToLogicalTree(LogicalTreeAttachmentEventArgs e) + protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e) { - base.OnAttachedToLogicalTree(e); - this.AddResourceBindingDisposable(TokenResourceBinder.CreateTokenBinding(this, BorderThicknessProperty, + base.OnAttachedToVisualTree(e); + _borderThicknessDisposable = TokenResourceBinder.CreateTokenBinding(this, BorderThicknessProperty, SharedTokenKey.BorderThickness, BindingPriority.Template, - new RenderScaleAwareThicknessConfigure(this))); + new RenderScaleAwareThicknessConfigure(this)); } - - protected override void OnDetachedFromLogicalTree(LogicalTreeAttachmentEventArgs e) + + protected override void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e) { - base.OnDetachedFromLogicalTree(e); - this.DisposeTokenBindings(); + base.OnDetachedFromVisualTree(e); + _borderThicknessDisposable?.Dispose(); } protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) diff --git a/src/AtomUI.Controls/Popup/Popup.cs b/src/AtomUI.Controls/Popup/Popup.cs index 92b16a44c..0b1f6c805 100644 --- a/src/AtomUI.Controls/Popup/Popup.cs +++ b/src/AtomUI.Controls/Popup/Popup.cs @@ -24,9 +24,7 @@ namespace AtomUI.Controls; using AvaloniaPopup = Avalonia.Controls.Primitives.Popup; -public class Popup : AvaloniaPopup, - IWaveSpiritAwareControl, - IResourceBindingManager +public class Popup : AvaloniaPopup, IWaveSpiritAwareControl { #region 公共属性定义 @@ -147,8 +145,6 @@ public class Popup : AvaloniaPopup, Control IMotionAwareControl.PropertyBindTarget => this; - CompositeDisposable? IResourceBindingManager.ResourceBindingsDisposable { get; set; } - #endregion internal BaseMotionActor? MotionActor; @@ -157,6 +153,7 @@ public class Popup : AvaloniaPopup, private IManagedPopupPositionerPopup? _managedPopupPositioner; private bool _isNeedDetectFlip = true; private bool _ignoreIsOpenChanged; + private CompositeDisposable? _tokenBindingDisposables; // 在翻转之后或者恢复正常,会有属性的变动,在变动之后捕捉动画需要等一个事件循环,保证布局已经生效 private bool _isNeedWaitFlipSync; @@ -204,16 +201,16 @@ public class Popup : AvaloniaPopup, protected override void OnAttachedToLogicalTree(LogicalTreeAttachmentEventArgs e) { base.OnAttachedToLogicalTree(e); - this.AddResourceBindingDisposable( - TokenResourceBinder.CreateTokenBinding(this, MaskShadowsProperty, SharedTokenKey.BoxShadowsSecondary)); - this.AddResourceBindingDisposable(TokenResourceBinder.CreateTokenBinding(this, MotionDurationProperty, + _tokenBindingDisposables = new CompositeDisposable(2); + _tokenBindingDisposables.Add(TokenResourceBinder.CreateTokenBinding(this, MaskShadowsProperty, SharedTokenKey.BoxShadowsSecondary)); + _tokenBindingDisposables.Add(TokenResourceBinder.CreateTokenBinding(this, MotionDurationProperty, SharedTokenKey.MotionDurationMid)); } protected override void OnDetachedFromLogicalTree(LogicalTreeAttachmentEventArgs e) { base.OnDetachedFromLogicalTree(e); - this.DisposeTokenBindings(); + _tokenBindingDisposables?.Dispose(); } protected Control? GetEffectivePlacementTarget() diff --git a/src/AtomUI.Controls/RadioButton/RadioIndicator.cs b/src/AtomUI.Controls/RadioButton/RadioIndicator.cs index 2da8c255b..f90820844 100644 --- a/src/AtomUI.Controls/RadioButton/RadioIndicator.cs +++ b/src/AtomUI.Controls/RadioButton/RadioIndicator.cs @@ -11,15 +11,12 @@ using Avalonia.Controls; using Avalonia.Controls.Primitives; using Avalonia.Data; using Avalonia.Interactivity; -using Avalonia.LogicalTree; using Avalonia.Media; using Avalonia.VisualTree; namespace AtomUI.Controls; -internal class RadioIndicator : Control, - IWaveAdornerInfoProvider, - IResourceBindingManager +internal class RadioIndicator : Control, IWaveAdornerInfoProvider { #region 公共属性定义 @@ -136,11 +133,11 @@ internal class RadioIndicator : Control, get => GetValue(IsWaveAnimationEnabledProperty); set => SetValue(IsWaveAnimationEnabledProperty, value); } - - CompositeDisposable? IResourceBindingManager.ResourceBindingsDisposable { get; set; } + #endregion private IPen? _cachedPen; + private IDisposable? _borderThicknessDisposable; static RadioIndicator() { @@ -164,28 +161,24 @@ internal class RadioIndicator : Control, base.OnUnloaded(e); Transitions = null; } - - protected override void OnAttachedToLogicalTree(LogicalTreeAttachmentEventArgs e) - { - base.OnAttachedToLogicalTree(e); - this.AddResourceBindingDisposable(TokenResourceBinder.CreateTokenBinding(this, RadioBorderThicknessProperty, - SharedTokenKey.BorderThickness, BindingPriority.Template, - new RenderScaleAwareThicknessConfigure(this))); - } - - protected override void OnDetachedFromLogicalTree(LogicalTreeAttachmentEventArgs e) - { - base.OnDetachedFromLogicalTree(e); - this.DisposeTokenBindings(); - } - + protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e) { base.OnAttachedToVisualTree(e); + _borderThicknessDisposable = TokenResourceBinder.CreateTokenBinding(this, RadioBorderThicknessProperty, + SharedTokenKey.BorderThickness, + BindingPriority.Template, + new RenderScaleAwareThicknessConfigure(this)); RadioDotEffectSize = CalculateDotSize(IsEnabled, IsChecked.HasValue && IsChecked.Value); UpdatePseudoClasses(); } + protected override void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e) + { + base.OnDetachedFromVisualTree(e); + _borderThicknessDisposable?.Dispose(); + } + private void ConfigureTransitions(bool force) { if (IsMotionEnabled) diff --git a/src/AtomUI.Controls/Switch/SwitchKnob.cs b/src/AtomUI.Controls/Switch/SwitchKnob.cs index a6d47e708..07fac9574 100644 --- a/src/AtomUI.Controls/Switch/SwitchKnob.cs +++ b/src/AtomUI.Controls/Switch/SwitchKnob.cs @@ -2,7 +2,6 @@ using System.Reactive.Disposables; using AtomUI.Controls.Utils; using AtomUI.Data; using AtomUI.Media; -using AtomUI.Theme; using AtomUI.Theme.Data; using AtomUI.Theme.Styling; using AtomUI.Utils; @@ -18,7 +17,7 @@ using Avalonia.VisualTree; namespace AtomUI.Controls; -internal class SwitchKnob : Control, IResourceBindingManager +internal class SwitchKnob : Control { #region 公共属性定义 @@ -119,13 +118,12 @@ internal class SwitchKnob : Control, IResourceBindingManager set => SetAndRaise(LoadingBgOpacityProperty, ref _loadingBgOpacity, value); } - CompositeDisposable? IResourceBindingManager.ResourceBindingsDisposable { get; set; } - #endregion private bool _isLoading; private CancellationTokenSource? _cancellationTokenSource; private IDisposable? _bindingDisposable; + private CompositeDisposable? _tokenBindingDisposables; static SwitchKnob() { @@ -254,16 +252,17 @@ internal class SwitchKnob : Control, IResourceBindingManager protected override void OnAttachedToLogicalTree(LogicalTreeAttachmentEventArgs e) { base.OnAttachedToLogicalTree(e); - this.AddResourceBindingDisposable(TokenResourceBinder.CreateTokenBinding(this, LoadingBgOpacityProperty, + _tokenBindingDisposables = new CompositeDisposable(2); + _tokenBindingDisposables.Add(TokenResourceBinder.CreateTokenBinding(this, LoadingBgOpacityProperty, ToggleSwitchTokenKey.SwitchDisabledOpacity)); - this.AddResourceBindingDisposable(TokenResourceBinder.CreateTokenBinding(this, LoadingAnimationDurationProperty, + _tokenBindingDisposables.Add(TokenResourceBinder.CreateTokenBinding(this, LoadingAnimationDurationProperty, ToggleSwitchTokenKey.LoadingAnimationDuration)); } protected override void OnDetachedFromLogicalTree(LogicalTreeAttachmentEventArgs e) { base.OnDetachedFromLogicalTree(e); - this.DisposeTokenBindings(); + _tokenBindingDisposables?.Dispose(); } protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e) diff --git a/src/AtomUI.Controls/TextBlock/SelectableTextBlock.cs b/src/AtomUI.Controls/TextBlock/SelectableTextBlock.cs index c6118adba..f7d90dea5 100644 --- a/src/AtomUI.Controls/TextBlock/SelectableTextBlock.cs +++ b/src/AtomUI.Controls/TextBlock/SelectableTextBlock.cs @@ -1,12 +1,13 @@ +using System.Reactive.Disposables; using AtomUI.Controls.Utils; using AtomUI.Media.TextFormatting; -using AtomUI.Theme; using AtomUI.Theme.Data; using AtomUI.Theme.Styling; using Avalonia; using Avalonia.Controls; using Avalonia.Input; using Avalonia.Interactivity; +using Avalonia.LogicalTree; using Avalonia.Media; using Avalonia.Media.TextFormatting; using Avalonia.Utilities; @@ -43,6 +44,7 @@ public class SelectableTextBlock : TextBlock private bool _canCopy; private int _wordSelectionStart = -1; + private CompositeDisposable? _tokenBindingDisposables; static SelectableTextBlock() { @@ -496,12 +498,19 @@ public class SelectableTextBlock : TextBlock return selectedText; } - protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e) + protected override void OnAttachedToLogicalTree(LogicalTreeAttachmentEventArgs e) { - base.OnAttachedToVisualTree(e); - this.AddResourceBindingDisposable(TokenResourceBinder.CreateTokenBinding(this, SelectionBrushProperty, + base.OnAttachedToLogicalTree(e); + _tokenBindingDisposables = new CompositeDisposable(2); + _tokenBindingDisposables.Add(TokenResourceBinder.CreateTokenBinding(this, SelectionBrushProperty, SharedTokenKey.SelectionBackground)); - this.AddResourceBindingDisposable(TokenResourceBinder.CreateTokenBinding(this, SelectionForegroundBrushProperty, + _tokenBindingDisposables.Add(TokenResourceBinder.CreateTokenBinding(this, SelectionForegroundBrushProperty, SharedTokenKey.SelectionForeground)); } + + protected override void OnDetachedFromLogicalTree(LogicalTreeAttachmentEventArgs e) + { + base.OnDetachedFromLogicalTree(e); + _tokenBindingDisposables?.Dispose(); + } } \ No newline at end of file