Browse Source

Rework Inference exit save to use IAsyncDisposable

pull/324/head
Ionite 12 months ago
parent
commit
db714590d9
No known key found for this signature in database
  1. 105
      StabilityMatrix.Avalonia/App.axaml.cs
  2. 15
      StabilityMatrix.Avalonia/ViewModels/InferenceViewModel.cs

105
StabilityMatrix.Avalonia/App.axaml.cs

@ -10,6 +10,7 @@ using System.Text.Json;
using System.Text.Json.Serialization; using System.Text.Json.Serialization;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using AsyncAwaitBestPractices;
using Avalonia; using Avalonia;
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Controls.ApplicationLifetimes; using Avalonia.Controls.ApplicationLifetimes;
@ -69,6 +70,8 @@ namespace StabilityMatrix.Avalonia;
public sealed class App : Application public sealed class App : Application
{ {
private static bool isAsyncDisposeComplete;
[NotNull] [NotNull]
public static IServiceProvider? Services { get; private set; } public static IServiceProvider? Services { get; private set; }
@ -220,23 +223,7 @@ public sealed class App : Application
mainWindow.WindowStartupLocation = WindowStartupLocation.CenterScreen; mainWindow.WindowStartupLocation = WindowStartupLocation.CenterScreen;
} }
mainWindow.Closing += (_, _) => mainWindow.Closing += OnMainWindowClosing;
{
var validWindowPosition = mainWindow.Screens.All.Any(screen => screen.Bounds.Contains(mainWindow.Position));
settingsManager.Transaction(
s =>
{
s.WindowSettings = new WindowSettings(
mainWindow.Width,
mainWindow.Height,
validWindowPosition ? mainWindow.Position.X : 0,
validWindowPosition ? mainWindow.Position.Y : 0
);
},
ignoreMissingLibraryDir: true
);
};
mainWindow.Closed += (_, _) => Shutdown(); mainWindow.Closed += (_, _) => Shutdown();
mainWindow.SetDefaultFonts(); mainWindow.SetDefaultFonts();
@ -596,6 +583,87 @@ public sealed class App : Application
} }
} }
/// <summary>
/// Handle shutdown requests (happens before <see cref="OnExit"/>)
/// </summary>
private static void OnMainWindowClosing(object? sender, WindowClosingEventArgs e)
{
if (e.Cancel)
return;
var mainWindow = (MainWindow)sender!;
// Show confirmation if package running
var launchPageViewModel = Services.GetRequiredService<LaunchPageViewModel>();
launchPageViewModel.OnMainWindowClosing(e);
if (e.Cancel)
return;
// Check if we need to dispose IAsyncDisposables
if (
!isAsyncDisposeComplete
&& Services.GetServices<IAsyncDisposable>().ToList() is { Count: > 0 } asyncDisposables
)
{
// Cancel shutdown for now
e.Cancel = true;
isAsyncDisposeComplete = true;
Debug.WriteLine("OnShutdownRequested Canceled: Disposing IAsyncDisposables");
Task.Run(async () =>
{
foreach (var disposable in asyncDisposables)
{
Debug.WriteLine($"Disposing IAsyncDisposable ({disposable.GetType().Name})");
try
{
await disposable.DisposeAsync().ConfigureAwait(false);
}
catch (Exception ex)
{
Debug.Fail(ex.ToString());
}
}
})
.ContinueWith(_ =>
{
// Shutdown again
Dispatcher.UIThread.Invoke(() => Shutdown());
})
.SafeFireAndForget();
return;
}
OnMainWindowClosingTerminal(mainWindow);
}
/// <summary>
/// Called at the end of <see cref="OnMainWindowClosing"/> before the main window is closed.
/// </summary>
private static void OnMainWindowClosingTerminal(Window sender)
{
var settingsManager = Services.GetRequiredService<ISettingsManager>();
// Save window position
var validWindowPosition = sender.Screens.All.Any(screen => screen.Bounds.Contains(sender.Position));
settingsManager.Transaction(
s =>
{
s.WindowSettings = new WindowSettings(
sender.Width,
sender.Height,
validWindowPosition ? sender.Position.X : 0,
validWindowPosition ? sender.Position.Y : 0
);
},
ignoreMissingLibraryDir: true
);
}
private static void OnExit(object? sender, ControlledApplicationLifetimeExitEventArgs args) private static void OnExit(object? sender, ControlledApplicationLifetimeExitEventArgs args)
{ {
Debug.WriteLine("Start OnExit"); Debug.WriteLine("Start OnExit");
@ -610,7 +678,8 @@ public sealed class App : Application
} }
Debug.WriteLine("Start OnExit: Disposing services"); Debug.WriteLine("Start OnExit: Disposing services");
// Dispose all services
// Dispose IDisposable services
foreach (var disposable in Services.GetServices<IDisposable>()) foreach (var disposable in Services.GetServices<IDisposable>())
{ {
Debug.WriteLine($"Disposing {disposable.GetType().Name}"); Debug.WriteLine($"Disposing {disposable.GetType().Name}");

15
StabilityMatrix.Avalonia/ViewModels/InferenceViewModel.cs

@ -41,8 +41,8 @@ namespace StabilityMatrix.Avalonia.ViewModels;
[Preload] [Preload]
[View(typeof(InferencePage))] [View(typeof(InferencePage))]
[Singleton] [Singleton, Singleton(typeof(IAsyncDisposable))]
public partial class InferenceViewModel : PageViewModelBase public partial class InferenceViewModel : PageViewModelBase, IAsyncDisposable
{ {
private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
private readonly INotificationService notificationService; private readonly INotificationService notificationService;
@ -230,16 +230,13 @@ public partial class InferenceViewModel : PageViewModelBase
} }
/// <summary> /// <summary>
/// On Unloaded, sync tab states to database /// On exit, sync tab states to database
/// </summary> /// </summary>
public override async Task OnUnloadedAsync() public async ValueTask DisposeAsync()
{ {
await base.OnUnloadedAsync();
if (Design.IsDesignMode)
return;
await SyncTabStatesWithDatabase(); await SyncTabStatesWithDatabase();
GC.SuppressFinalize(this);
} }
private void OnInferenceTextToImageRequested(object? sender, LocalImageFile e) private void OnInferenceTextToImageRequested(object? sender, LocalImageFile e)

Loading…
Cancel
Save