From d2aa8e6520c01f7c3a279ebf05ffff9bb52ff560 Mon Sep 17 00:00:00 2001 From: workgroupengineering Date: Tue, 21 Nov 2023 12:07:09 +0100 Subject: [PATCH] fix: Potential TransformGroup memory leak (#13529) * fix: Potential TransformGroup memoey leak * fix: Address review * fix: Address review * fix: review --- src/Avalonia.Base/Media/TransformGroup.cs | 44 ++++++++++++++++------- 1 file changed, 31 insertions(+), 13 deletions(-) diff --git a/src/Avalonia.Base/Media/TransformGroup.cs b/src/Avalonia.Base/Media/TransformGroup.cs index 38069f783a..8f9ab67712 100644 --- a/src/Avalonia.Base/Media/TransformGroup.cs +++ b/src/Avalonia.Base/Media/TransformGroup.cs @@ -1,3 +1,4 @@ +using System; using Avalonia.Collections; using Avalonia.Metadata; @@ -11,25 +12,17 @@ namespace Avalonia.Media public static readonly StyledProperty ChildrenProperty = AvaloniaProperty.Register(nameof(Children)); - [System.Diagnostics.CodeAnalysis.SuppressMessage("AvaloniaProperty", "AVP1012", + private IDisposable? _childrenNotificationSubscription; + private readonly EventHandler _childTransformChangedHandler; + + [System.Diagnostics.CodeAnalysis.SuppressMessage("AvaloniaProperty", "AVP1012", Justification = "Collection properties shouldn't be set with SetCurrentValue.")] public TransformGroup() { + _childTransformChangedHandler = (_, _) => RaiseChanged(); Children = new Transforms(); - Children.ResetBehavior = ResetBehavior.Remove; - Children.CollectionChanged += delegate - { - Children.ForEachItem( - (tr) => tr.Changed += ChildTransform_Changed, - (tr) => tr.Changed -= ChildTransform_Changed, - () => { }); - }; } - private void ChildTransform_Changed(object? sender, System.EventArgs e) - { - this.RaiseChanged(); - } /// /// Gets or sets the children. @@ -61,6 +54,31 @@ namespace Avalonia.Media return result; } } + + protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) + { + base.OnPropertyChanged(change); + if (change.Property == ChildrenProperty) + { + _childrenNotificationSubscription?.Dispose(); + if (change.OldValue is Transforms oldTransforms) + { + foreach (var item in oldTransforms) + { + item.Changed -= _childTransformChangedHandler; + } + } + if (change.NewValue is Transforms newTransforms) + { + // Ensure reset behavior is Remove + newTransforms.ResetBehavior = ResetBehavior.Remove; + _childrenNotificationSubscription = newTransforms.ForEachItem( + (tr) => tr.Changed += _childTransformChangedHandler, + (tr) => tr.Changed -= _childTransformChangedHandler, + () => { }); + } + } + } } public sealed class Transforms : AvaloniaList