Fix ProgressBar memory leak

This commit is contained in:
chinboy
2025-03-02 14:48:49 +08:00
parent 30a6e92bf3
commit b75f4cd743
3 changed files with 52 additions and 29 deletions
@@ -1,5 +1,6 @@
using AtomUI.IconPkg;
using AtomUI.IconPkg.AntDesign;
using AtomUI.Theme;
using AtomUI.Theme.Data;
using AtomUI.Theme.Styling;
using Avalonia;
@@ -16,13 +17,13 @@ internal class AbstractCircleProgressTheme : AbstractProgressBarTheme
{
}
protected override void NotifyBuildControlTemplate(AbstractProgressBar bar, INameScope scope, Canvas container)
protected override void NotifyBuildControlTemplate(AbstractProgressBar progressBar, INameScope scope, Canvas container)
{
base.NotifyBuildControlTemplate(bar, scope, container);
CreateCompletedIcons(scope, container);
base.NotifyBuildControlTemplate(progressBar, scope, container);
CreateCompletedIcons(progressBar, scope, container);
}
private void CreateCompletedIcons(INameScope scope, Canvas container)
private void CreateCompletedIcons(AbstractProgressBar progressBar, INameScope scope, Canvas container)
{
var exceptionCompletedIcon = AntDesignIconPackage.CloseOutlined();
exceptionCompletedIcon.Name = ExceptionCompletedIconPart;
@@ -30,10 +31,10 @@ internal class AbstractCircleProgressTheme : AbstractProgressBarTheme
exceptionCompletedIcon.VerticalAlignment = VerticalAlignment.Center;
exceptionCompletedIcon.RegisterInNameScope(scope);
TokenResourceBinder.CreateTokenBinding(exceptionCompletedIcon, Icon.NormalFilledBrushProperty,
SharedTokenKey.ColorError);
TokenResourceBinder.CreateTokenBinding(exceptionCompletedIcon, Icon.DisabledFilledBrushProperty,
SharedTokenKey.ControlItemBgActiveDisabled);
progressBar.AddTokenBindingDisposable(TokenResourceBinder.CreateTokenBinding(exceptionCompletedIcon, Icon.NormalFilledBrushProperty,
SharedTokenKey.ColorError));
progressBar.AddTokenBindingDisposable(TokenResourceBinder.CreateTokenBinding(exceptionCompletedIcon, Icon.DisabledFilledBrushProperty,
SharedTokenKey.ControlItemBgActiveDisabled));
var successCompletedIcon = AntDesignIconPackage.CheckOutlined();
successCompletedIcon.Name = SuccessCompletedIconPart;
@@ -41,10 +42,10 @@ internal class AbstractCircleProgressTheme : AbstractProgressBarTheme
successCompletedIcon.VerticalAlignment = VerticalAlignment.Center;
successCompletedIcon.RegisterInNameScope(scope);
TokenResourceBinder.CreateTokenBinding(successCompletedIcon, Icon.NormalFilledBrushProperty,
SharedTokenKey.ColorSuccess);
TokenResourceBinder.CreateTokenBinding(successCompletedIcon, Icon.DisabledFilledBrushProperty,
SharedTokenKey.ControlItemBgActiveDisabled);
progressBar.AddTokenBindingDisposable(TokenResourceBinder.CreateTokenBinding(successCompletedIcon, Icon.NormalFilledBrushProperty,
SharedTokenKey.ColorSuccess));
progressBar.AddTokenBindingDisposable(TokenResourceBinder.CreateTokenBinding(successCompletedIcon, Icon.DisabledFilledBrushProperty,
SharedTokenKey.ControlItemBgActiveDisabled));
container.Children.Add(exceptionCompletedIcon);
container.Children.Add(successCompletedIcon);
@@ -1,5 +1,6 @@
using AtomUI.IconPkg;
using AtomUI.IconPkg.AntDesign;
using AtomUI.Theme;
using AtomUI.Theme.Data;
using AtomUI.Theme.Styling;
using Avalonia.Controls;
@@ -19,30 +20,34 @@ internal class AbstractLineProgressTheme : AbstractProgressBarTheme
protected override void NotifyBuildControlTemplate(AbstractProgressBar bar, INameScope scope, Canvas container)
{
base.NotifyBuildControlTemplate(bar, scope, container);
CreateCompletedIcons(scope, container);
CreateCompletedIcons(bar, scope, container);
}
private void CreateCompletedIcons(INameScope scope, Canvas container)
private void CreateCompletedIcons(AbstractProgressBar progressBar, INameScope scope, Canvas container)
{
var exceptionCompletedIcon = AntDesignIconPackage.CloseCircleFilled();
exceptionCompletedIcon.Name = ExceptionCompletedIconPart;
exceptionCompletedIcon.HorizontalAlignment = HorizontalAlignment.Left;
exceptionCompletedIcon.RegisterInNameScope(scope);
TokenResourceBinder.CreateTokenBinding(exceptionCompletedIcon, Icon.NormalFilledBrushProperty,
SharedTokenKey.ColorError);
TokenResourceBinder.CreateTokenBinding(exceptionCompletedIcon, Icon.DisabledFilledBrushProperty,
SharedTokenKey.ControlItemBgActiveDisabled);
progressBar.AddTokenBindingDisposable(TokenResourceBinder.CreateTokenBinding(exceptionCompletedIcon,
Icon.NormalFilledBrushProperty,
SharedTokenKey.ColorError));
progressBar.AddTokenBindingDisposable(TokenResourceBinder.CreateTokenBinding(exceptionCompletedIcon,
Icon.DisabledFilledBrushProperty,
SharedTokenKey.ControlItemBgActiveDisabled));
var successCompletedIcon = AntDesignIconPackage.CheckCircleFilled();
successCompletedIcon.Name = SuccessCompletedIconPart;
successCompletedIcon.HorizontalAlignment = HorizontalAlignment.Left;
successCompletedIcon.RegisterInNameScope(scope);
TokenResourceBinder.CreateTokenBinding(successCompletedIcon, Icon.NormalFilledBrushProperty,
SharedTokenKey.ColorSuccess);
TokenResourceBinder.CreateTokenBinding(successCompletedIcon, Icon.DisabledFilledBrushProperty,
SharedTokenKey.ControlItemBgActiveDisabled);
progressBar.AddTokenBindingDisposable(TokenResourceBinder.CreateTokenBinding(successCompletedIcon,
Icon.NormalFilledBrushProperty,
SharedTokenKey.ColorSuccess));
progressBar.AddTokenBindingDisposable(TokenResourceBinder.CreateTokenBinding(successCompletedIcon,
Icon.DisabledFilledBrushProperty,
SharedTokenKey.ControlItemBgActiveDisabled));
container.Children.Add(exceptionCompletedIcon);
container.Children.Add(successCompletedIcon);
@@ -1,3 +1,4 @@
using System.Reactive.Disposables;
using AtomUI.IconPkg;
using AtomUI.Media;
using AtomUI.Theme;
@@ -12,6 +13,7 @@ using Avalonia.Controls;
using Avalonia.Controls.Metadata;
using Avalonia.Controls.Primitives;
using Avalonia.Data;
using Avalonia.LogicalTree;
using Avalonia.Media;
using AnimationUtils = AtomUI.Controls.Utils.AnimationUtils;
@@ -29,7 +31,8 @@ public enum ProgressStatus
public abstract class AbstractProgressBar : RangeBase,
ISizeTypeAware,
IAnimationAwareControl,
IControlSharedTokenResourcesHost
IControlSharedTokenResourcesHost,
ITokenResourceConsumer
{
protected const double LARGE_STROKE_THICKNESS = 8;
protected const double MIDDLE_STROKE_THICKNESS = 6;
@@ -269,9 +272,11 @@ public abstract class AbstractProgressBar : RangeBase,
Control IAnimationAwareControl.PropertyBindTarget => this;
Control IControlSharedTokenResourcesHost.HostControl => this;
string IControlSharedTokenResourcesHost.TokenId => ProgressBarToken.ID;
CompositeDisposable? ITokenResourceConsumer.TokenBindingsDisposable => _tokenBindingsDisposable;
#endregion
private CompositeDisposable? _tokenBindingsDisposable;
protected LayoutTransformControl? _layoutTransformLabel;
protected Label? _percentageLabel;
protected Icon? _successCompletedIcon;
@@ -346,7 +351,6 @@ public abstract class AbstractProgressBar : RangeBase,
_percentageLabel = scope.Find<Label>(AbstractProgressBarTheme.PercentageLabelPart);
_exceptionCompletedIcon = scope.Find<Icon>(AbstractProgressBarTheme.ExceptionCompletedIconPart);
_successCompletedIcon = scope.Find<Icon>(AbstractProgressBarTheme.SuccessCompletedIconPart);
SetupTokenBindings();
NotifySetupUI();
}
@@ -476,8 +480,8 @@ public abstract class AbstractProgressBar : RangeBase,
protected virtual void NotifySetupTokenBindings()
{
TokenResourceBinder.CreateTokenBinding(this, SuccessThresholdBrushProperty,
SharedTokenKey.ColorSuccess);
this.AddTokenBindingDisposable(TokenResourceBinder.CreateTokenBinding(this, SuccessThresholdBrushProperty,
SharedTokenKey.ColorSuccess));
}
protected virtual void NotifyPropertyChanged(AvaloniaPropertyChangedEventArgs e)
@@ -505,5 +509,18 @@ public abstract class AbstractProgressBar : RangeBase,
protected virtual void NotifyPrepareDrawingContext(DrawingContext context)
{
}
protected override void OnAttachedToLogicalTree(LogicalTreeAttachmentEventArgs e)
{
base.OnAttachedToLogicalTree(e);
_tokenBindingsDisposable = new CompositeDisposable();
SetupTokenBindings();
}
protected override void OnDetachedFromLogicalTree(LogicalTreeAttachmentEventArgs e)
{
base.OnDetachedFromLogicalTree(e);
this.DisposeTokenBindings();
}
}