Skip to content

Commit

Permalink
Memory Leak in Style with Trigger - fix (#22503)
Browse files Browse the repository at this point in the history
* Fix #22036

* Added a XAML test #22036
  • Loading branch information
kubaflo authored Jun 3, 2024
1 parent 7d21950 commit c62fc0d
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 4 deletions.
15 changes: 11 additions & 4 deletions src/Controls/src/Core/Interactivity/EventTrigger.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ namespace Microsoft.Maui.Controls
public sealed class EventTrigger : TriggerBase
{
static readonly MethodInfo s_handlerinfo = typeof(EventTrigger).GetRuntimeMethods().Single(mi => mi.Name == "OnEventTriggered" && mi.IsPublic == false);
readonly List<BindableObject> _associatedObjects = new List<BindableObject>();
readonly List<WeakReference<BindableObject>> _associatedObjects = new List<WeakReference<BindableObject>>();

EventInfo _eventinfo;

Expand Down Expand Up @@ -50,13 +50,20 @@ internal override void OnAttachedTo(BindableObject bindable)
base.OnAttachedTo(bindable);
if (!string.IsNullOrEmpty(Event))
AttachHandlerTo(bindable);
_associatedObjects.Add(bindable);
_associatedObjects.Add(new WeakReference<BindableObject>(bindable));
}

internal override void OnDetachingFrom(BindableObject bindable)
{
_associatedObjects.Remove(bindable);
DetachHandlerFrom(bindable);
_associatedObjects.RemoveAll(wr =>
{
if (wr.TryGetTarget(out var target) && target == bindable)
{
DetachHandlerFrom(bindable);
return true;
}
return false;
});
base.OnDetachingFrom(bindable);
}

Expand Down
4 changes: 4 additions & 0 deletions src/Controls/tests/Xaml.UnitTests/Issues/Maui22036.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Microsoft.Maui.Controls.Xaml.UnitTests.Maui22036"/>
58 changes: 58 additions & 0 deletions src/Controls/tests/Xaml.UnitTests/Issues/Maui22036.xaml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
using System;
using System.Threading.Tasks;
using Microsoft.Maui.ApplicationModel;
using Microsoft.Maui.Controls.Core.UnitTests;
using Microsoft.Maui.Dispatching;
using Microsoft.Maui.UnitTests;
using NUnit.Framework;

namespace Microsoft.Maui.Controls.Xaml.UnitTests;

public partial class Maui22036
{
public Maui22036()
{
InitializeComponent();
}

public Maui22036(bool useCompiledXaml)
{
//this stub will be replaced at compile time
}

[TestFixture]
class Test
{
[SetUp]
public void Setup()
{
Application.SetCurrentApplication(new MockApplication());
DispatcherProvider.SetCurrent(new DispatcherProviderStub());
}

[TearDown] public void TearDown() => AppInfo.SetCurrent(null);

[Test]
public async Task StyleWithTriggerLeak([Values(false, true)] bool useCompiledXaml)
{
var style = new Style(typeof(ContentPage));
var trigger = new EventTrigger { Event = nameof(Appearing) };
trigger.Actions.Add(new EmptyTriggerAction());
style.Triggers.Add(trigger);

Application.Current.Resources.Add(style);

var pagewr = new WeakReference(new Maui22036(useCompiledXaml));
await Task.Delay(10);
GC.Collect();
Assert.IsNull(pagewr.Target, "Page leaked");
}
}

class EmptyTriggerAction : TriggerAction<ContentPage>
{
protected override void Invoke(ContentPage sender)
{
}
}
}

0 comments on commit c62fc0d

Please sign in to comment.