Edit: this was merged to master. See documentation here: https://github.com/AvaloniaUI/Avalonia/wiki/Application-lifetimes
TL;DR: Platforms are not created equal.
There are things we can and can not do at certain points at every platform. Some of the platforms allow us to have our own event loop, some dont and some force us to do so.
Some platforms have no builtin application lifetime management, some have opt-out one, some have enforced one.
Mobile platforms can kill your app at any point of time when running low on system resources, applications are expected to persist their state if that happens.
Basically we can not expect to have WPF-style startup and shutdown sequence everywhere.
So we'll remove WPF-style stuff from Application class completely (alongside with RegisterServices and other garbage that was historically there).
Instead there would be OnFrameworkInitializationCompleted method that would accept event args that contain IApplicationLifetime instance.
interface IApplicationLifetime
{
// Application is initialized, APIs can be called
event Action Initialized;
// Event is fired for a fresh start without any saved state
event Action Starting;
// Event is fired when resuming from a saved state, Starting isn't called in this case
event Action<ResumeContext> Resuming;
// Event is fired when save state is required
event Action<SaveContext> Saving;
}
// WPF-style lifetime management for applicable platforms
interface IControlledApplicationLifetime : IApplicationLifetime
{
Window MainWindow {get;set;}
ShutdownMode ShutdownMode{get;set;}
void Shutdown();
}
On desktop platforms we'll have a way to start the run loop manually (with CancellationToken or IClosable) or use controlled application lifetime for WPF-style experience.
Application.Run overloads will be marked as deprecated and will just run the event loop without any lifetime service.
e. g.
class Program
{
// Initialization code. Don't use any Avalonia, third-party APIs or any
// SynchronizationContext-reliant code before OnFrameworkInitializationCompleted is called: things aren't initialized
// yet and stuff might break.
public static void Main(string[] args) => BuildAvaloniaApp().StartWithControlledLifetime();
// Avalonia configuration, don't remove; also used by visual designer.
public static AppBuilder BuildAvaloniaApp()
=> AppBuilder.Configure<App>()
.UsePlatformDetect()
.LogToDebug();
}
class Application : App
{
public override void Initialize()
{
AvaloniaXamlLoader.Load(this);
}
public override void OnFrameworkInitializationCompleted(FrameworkInitializationEventArgs args)
{
if(args.Lifetime is IControlledApplicationLifetime cal)
{
// Do WPF-like stuff
}
}
}
Lifetime management should be optional, so there will be a way to run the app like this:
// Initialization code. Don't use any Avalonia, third-party APIs or any
// SynchronizationContext-reliant code before AppMain is called: things aren't initialized
// yet and stuff might break.
public static void Main(string[] args) => BuildAvaloniaApp().Start(AppMain, args);
// Avalonia configuration, don't remove; also used by visual designer.
public static AppBuilder BuildAvaloniaApp()
=> AppBuilder.Configure<App>()
.UsePlatformDetect()
.LogToDebug();
// Your application's entry point. Here you can initialize your MVVM framework, DI
// container, etc.
private static void AppMain(string[] args)
{
Dispatcher.MainLoop(new MainWindow());
}
@Gillibald @jkoritzinsky
AppBuilder)In all scenarios the FrameworkInitializationCompleted event is raised so thats the common starting point for every platform. Things like actual IApplicationLifetime implementation come from the AppBuilder.
I think I'll mark all Run overloads as deprecated except CancellationToken one since it's pretty much required for implementing a custom lifetime on desktop platforms.
If we leave Run on Application it is not clear that this isn't supported on all platforms. This should be an external component configured by AppBuilder.
Most helpful comment
@Gillibald @jkoritzinsky