using System; using System.Diagnostics.CodeAnalysis; using Avalonia.Controls; using Avalonia.Controls.ApplicationLifetimes; using Avalonia.Reactive; using Avalonia.Threading; using Avalonia.UnitTests; using Xunit; namespace Avalonia.LeakTests; internal class ViewModelForDisposingTest { [SuppressMessage("ReSharper", "EmptyDestructor", Justification = "Needed for test")] ~ViewModelForDisposingTest() { } } public class DataContextTests : ScopedTestBase { [Fact] public void Window_DataContext_Disposed_After_Window_Close_With_Lifetime() { static IDisposable Run(out WeakReference weakDataContext) { var unitTestApp = UnitTestApplication.Start(TestServices.StyledWindow); var lifetime = new ClassicDesktopStyleApplicationLifetime(); lifetime.ShutdownMode = ShutdownMode.OnExplicitShutdown; var viewModel = new ViewModelForDisposingTest(); var window = new Window { DataContext = viewModel }; window.Show(); window.Close(); var disposable = Disposable.Create(lifetime, lt => lt.Shutdown()) .DisposeWith(new CompositeDisposable(lifetime, unitTestApp)); weakDataContext = new WeakReference(viewModel); return disposable; } using var _ = Run(out var weakDataContext); Assert.True(weakDataContext.IsAlive); CollectGarbage(); Assert.False(weakDataContext.IsAlive); } [Fact] public void Window_DataContext_Disposed_After_Window_Close_Without_Lifetime() { static void Run(out WeakReference weakDataContext) { using var _ = UnitTestApplication.Start(TestServices.StyledWindow); var viewModel = new ViewModelForDisposingTest(); var window = new Window { DataContext = viewModel }; window.Show(); window.Close(); weakDataContext = new WeakReference(viewModel); } Run(out var weakDataContext); Assert.True(weakDataContext.IsAlive); CollectGarbage(); Assert.False(weakDataContext.IsAlive); } private static void CollectGarbage() { // Process all Loaded events to free control reference(s) Dispatcher.UIThread.RunJobs(DispatcherPriority.Loaded); GC.Collect(); } }