A cross-platform UI framework for .NET
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

89 lines
3.6 KiB

using Avalonia;
using Avalonia.VisualTree;
using Avalonia.Controls;
using System.Threading;
using System.Reactive;
using System.Reactive.Disposables;
using System.Reactive.Subjects;
using System.Reactive.Linq;
using ReactiveUI;
using System;
using Avalonia.Controls.ApplicationLifetimes;
using Splat;
namespace Avalonia.ReactiveUI
{
/// <summary>
/// A ReactiveUI AutoSuspendHelper which initializes suspension hooks for
/// Avalonia applications. Call its constructor in your app's composition root,
/// before calling the RxApp.SuspensionHost.SetupDefaultSuspendResume method.
/// </summary>
public sealed class AutoSuspendHelper : IEnableLogger, IDisposable
{
private readonly Subject<IDisposable> _shouldPersistState = new Subject<IDisposable>();
private readonly Subject<Unit> _isLaunchingNew = new Subject<Unit>();
/// <summary>
/// Initializes a new instance of the <see cref="AutoSuspendHelper"/> class.
/// </summary>
/// <param name="lifetime">Pass in the Application.ApplicationLifetime property.</param>
public AutoSuspendHelper(IApplicationLifetime lifetime)
{
RxApp.SuspensionHost.IsResuming = Observable.Never<Unit>();
RxApp.SuspensionHost.IsLaunchingNew = _isLaunchingNew;
if (Avalonia.Controls.Design.IsDesignMode)
{
this.Log().Debug("Design mode detected. AutoSuspendHelper won't persist app state.");
RxApp.SuspensionHost.ShouldPersistState = Observable.Never<IDisposable>();
}
else if (lifetime is IControlledApplicationLifetime controlled)
{
this.Log().Debug("Using IControlledApplicationLifetime events to handle app exit.");
controlled.Exit += (sender, args) => OnControlledApplicationLifetimeExit();
RxApp.SuspensionHost.ShouldPersistState = _shouldPersistState;
}
else if (lifetime != null)
{
var type = lifetime.GetType().FullName;
var message = $"Don't know how to detect app exit event for {type}.";
throw new NotSupportedException(message);
}
else
{
var message = "ApplicationLifetime is null. "
+ "Ensure you are initializing AutoSuspendHelper "
+ "after Avalonia application initialization is completed.";
throw new ArgumentNullException(message);
}
var errored = new Subject<Unit>();
AppDomain.CurrentDomain.UnhandledException += (o, e) => errored.OnNext(Unit.Default);
RxApp.SuspensionHost.ShouldInvalidateState = errored;
}
/// <summary>
/// Call this method in your App.OnFrameworkInitializationCompleted method.
/// </summary>
public void OnFrameworkInitializationCompleted() => _isLaunchingNew.OnNext(Unit.Default);
/// <summary>
/// Disposes internally stored observers.
/// </summary>
public void Dispose()
{
_shouldPersistState.Dispose();
_isLaunchingNew.Dispose();
}
private void OnControlledApplicationLifetimeExit()
{
this.Log().Debug("Received IControlledApplicationLifetime exit event.");
var manual = new ManualResetEvent(false);
_shouldPersistState.OnNext(Disposable.Create(() => manual.Set()));
manual.WaitOne();
this.Log().Debug("Completed actions on IControlledApplicationLifetime exit event.");
}
}
}