diff --git a/src/Avalonia.Controls/TopLevel.cs b/src/Avalonia.Controls/TopLevel.cs index f314629d02..1853d67019 100644 --- a/src/Avalonia.Controls/TopLevel.cs +++ b/src/Avalonia.Controls/TopLevel.cs @@ -184,7 +184,7 @@ namespace Avalonia.Controls /// /// Gets the renderer for the window. /// - public IRenderer Renderer { get; } + public IRenderer Renderer { get; private set; } /// /// Gets the access key handler for the window. @@ -381,6 +381,8 @@ namespace Avalonia.Controls private void HandleClosed() { Closed?.Invoke(this, EventArgs.Empty); + Renderer?.Dispose(); + Renderer = null; _applicationLifecycle.OnExit -= OnApplicationExiting; } diff --git a/tests/Avalonia.LeakTests/ControlTests.cs b/tests/Avalonia.LeakTests/ControlTests.cs index 1e257a698c..23670257ff 100644 --- a/tests/Avalonia.LeakTests/ControlTests.cs +++ b/tests/Avalonia.LeakTests/ControlTests.cs @@ -11,6 +11,7 @@ using Avalonia.Controls.Primitives; using Avalonia.Controls.Templates; using Avalonia.Diagnostics; using Avalonia.Layout; +using Avalonia.Platform; using Avalonia.Rendering; using Avalonia.Styling; using Avalonia.UnitTests; @@ -301,6 +302,33 @@ namespace Avalonia.LeakTests } } + + [Fact] + public void RendererIsDisposed() + { + using (UnitTestApplication.Start(TestServices.StyledWindow)) + { + var renderer = new Mock(); + renderer.Setup(x => x.Dispose()); + var impl = new Mock(); + impl.SetupGet(x => x.Scaling).Returns(1); + impl.SetupProperty(x => x.Closed); + impl.Setup(x => x.Dispose()).Callback(() => impl.Object.Closed()); + + AvaloniaLocator.CurrentMutable.Bind() + .ToConstant(new MockWindowingPlatform(() => impl.Object)); + AvaloniaLocator.CurrentMutable.Bind() + .ToConstant(new MockRendererFactory(renderer.Object)); + var window = new Window() + { + Content = new Button() + }; + window.Show(); + window.Close(); + renderer.Verify(r => r.Dispose()); + } + } + private static void PurgeMoqReferences() { // Moq holds onto references in its mock of IRenderer in case we want to check if a method has been called; diff --git a/tests/Avalonia.UnitTests/Avalonia.UnitTests.csproj b/tests/Avalonia.UnitTests/Avalonia.UnitTests.csproj index 7a84243953..f7878ab91a 100644 --- a/tests/Avalonia.UnitTests/Avalonia.UnitTests.csproj +++ b/tests/Avalonia.UnitTests/Avalonia.UnitTests.csproj @@ -55,6 +55,7 @@ + diff --git a/tests/Avalonia.UnitTests/MockRendererFactory.cs b/tests/Avalonia.UnitTests/MockRendererFactory.cs new file mode 100644 index 0000000000..e62012b13c --- /dev/null +++ b/tests/Avalonia.UnitTests/MockRendererFactory.cs @@ -0,0 +1,29 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Avalonia.Rendering; + +namespace Avalonia.UnitTests +{ + public class MockRendererFactory : IRendererFactory + { + private readonly Func _cb; + + public MockRendererFactory(Func cb = null) + { + _cb = cb; + } + + public MockRendererFactory(IRenderer renderer) : this((_, __) => renderer) + { + + } + + public IRenderer CreateRenderer(IRenderRoot root, IRenderLoop renderLoop) + { + return _cb?.Invoke(root, renderLoop); + } + } +}