diff --git a/src/Avalonia.Controls/Flyouts/FlyoutBase.cs b/src/Avalonia.Controls/Flyouts/FlyoutBase.cs
index 4801fa69f0..1504d2b25f 100644
--- a/src/Avalonia.Controls/Flyouts/FlyoutBase.cs
+++ b/src/Avalonia.Controls/Flyouts/FlyoutBase.cs
@@ -223,6 +223,7 @@ namespace Avalonia.Controls.Primitives
{
Popup.PlacementTarget = Target = placementTarget;
((ISetLogicalParent)Popup).SetParent(placementTarget);
+ Popup.SetValue(StyledElement.TemplatedParentProperty, placementTarget.TemplatedParent);
}
if (Popup.Child == null)
diff --git a/src/Avalonia.Controls/Primitives/Popup.cs b/src/Avalonia.Controls/Primitives/Popup.cs
index 95e5e25c42..1501d97470 100644
--- a/src/Avalonia.Controls/Primitives/Popup.cs
+++ b/src/Avalonia.Controls/Primitives/Popup.cs
@@ -860,22 +860,7 @@ namespace Avalonia.Controls.Primitives
{
if (control != null)
{
- var templatedParent = TemplatedParent;
-
- if (control.TemplatedParent == null)
- {
- control.SetValue(TemplatedParentProperty, templatedParent);
- }
-
- control.ApplyTemplate();
-
- if (!(control is IPresenter) && control.TemplatedParent == templatedParent)
- {
- foreach (IControl child in control.VisualChildren)
- {
- SetTemplatedParentAndApplyChildTemplates(child);
- }
- }
+ TemplatedControl.ApplyTemplatedParent(control, TemplatedParent);
}
}
diff --git a/src/Avalonia.Controls/Primitives/TemplatedControl.cs b/src/Avalonia.Controls/Primitives/TemplatedControl.cs
index db029d38c0..4403bfce51 100644
--- a/src/Avalonia.Controls/Primitives/TemplatedControl.cs
+++ b/src/Avalonia.Controls/Primitives/TemplatedControl.cs
@@ -285,7 +285,7 @@ namespace Avalonia.Controls.Primitives
Logger.TryGet(LogEventLevel.Verbose, LogArea.Control)?.Log(this, "Creating control template");
var (child, nameScope) = template.Build(this);
- ApplyTemplatedParent(child);
+ ApplyTemplatedParent(child, this);
((ISetLogicalParent)child).SetParent(this);
VisualChildren.Add(child);
@@ -387,18 +387,18 @@ namespace Avalonia.Controls.Primitives
/// Sets the TemplatedParent property for the created template children.
///
/// The control.
- private void ApplyTemplatedParent(IControl control)
+ internal static void ApplyTemplatedParent(IStyledElement control, ITemplatedControl? templatedParent)
{
- control.SetValue(TemplatedParentProperty, this);
+ control.SetValue(TemplatedParentProperty, templatedParent);
var children = control.LogicalChildren;
var count = children.Count;
for (var i = 0; i < count; i++)
{
- if (children[i] is IControl child)
+ if (children[i] is IStyledElement child)
{
- ApplyTemplatedParent(child);
+ ApplyTemplatedParent(child, templatedParent);
}
}
}
diff --git a/src/Avalonia.Controls/ToolTip.cs b/src/Avalonia.Controls/ToolTip.cs
index 91c93c87c8..bb18bf4c64 100644
--- a/src/Avalonia.Controls/ToolTip.cs
+++ b/src/Avalonia.Controls/ToolTip.cs
@@ -271,8 +271,9 @@ namespace Avalonia.Controls
_popupHost = OverlayPopupHost.CreatePopupHost(control, null);
_popupHost.SetChild(this);
((ISetLogicalParent)_popupHost).SetParent(control);
-
- _popupHost.ConfigurePosition(control, GetPlacement(control),
+ ApplyTemplatedParent(this, control.TemplatedParent);
+
+ _popupHost.ConfigurePosition(control, GetPlacement(control),
new Point(GetHorizontalOffset(control), GetVerticalOffset(control)));
WindowManagerAddShadowHintChanged(_popupHost, false);
diff --git a/tests/Avalonia.LeakTests/ControlTests.cs b/tests/Avalonia.LeakTests/ControlTests.cs
index 8c05f2a0a7..6fb7b1448c 100644
--- a/tests/Avalonia.LeakTests/ControlTests.cs
+++ b/tests/Avalonia.LeakTests/ControlTests.cs
@@ -7,6 +7,7 @@ using System.Reactive.Disposables;
using Avalonia.Collections;
using Avalonia.Controls;
using Avalonia.Controls.Presenters;
+using Avalonia.Controls.Primitives;
using Avalonia.Controls.Shapes;
using Avalonia.Controls.Templates;
using Avalonia.Data;
@@ -877,6 +878,110 @@ namespace Avalonia.LeakTests
}
}
+ [Fact]
+ public void ToolTip_Is_Freed()
+ {
+ using (Start())
+ {
+ Func run = () =>
+ {
+ var window = new Window();
+ var source = new Button
+ {
+ Template = new FuncControlTemplate