|
|
|
@ -43,8 +43,8 @@ namespace Avalonia |
|
|
|
private readonly Styler _styler = new Styler(); |
|
|
|
private Styles _styles; |
|
|
|
private IResourceDictionary _resources; |
|
|
|
|
|
|
|
private CancellationTokenSource _mainLoopCancellationTokenSource; |
|
|
|
private int _exitCode; |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Initializes a new instance of the <see cref="Application"/> class.
|
|
|
|
@ -52,10 +52,14 @@ namespace Avalonia |
|
|
|
public Application() |
|
|
|
{ |
|
|
|
Windows = new WindowCollection(this); |
|
|
|
|
|
|
|
OnExit += OnExiting; |
|
|
|
} |
|
|
|
|
|
|
|
/// <inheritdoc/>
|
|
|
|
public event EventHandler<StartupEventArgs> Startup; |
|
|
|
|
|
|
|
/// <inheritdoc/>
|
|
|
|
public event EventHandler<ExitEventArgs> Exit; |
|
|
|
|
|
|
|
/// <inheritdoc/>
|
|
|
|
public event EventHandler<ResourcesChangedEventArgs> ResourcesChanged; |
|
|
|
|
|
|
|
@ -164,14 +168,14 @@ namespace Avalonia |
|
|
|
IResourceNode IResourceNode.ResourceParent => null; |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Gets or sets the <see cref="ExitMode"/>. This property indicates whether the application exits explicitly or implicitly.
|
|
|
|
/// If <see cref="ExitMode"/> is set to OnExplicitExit the application is only closes if Exit is called.
|
|
|
|
/// Gets or sets the <see cref="ShutdownMode"/>. This property indicates whether the application is shutdown explicitly or implicitly.
|
|
|
|
/// If <see cref="ShutdownMode"/> is set to OnExplicitShutdown the application is only closes if Shutdown is called.
|
|
|
|
/// The default is OnLastWindowClose
|
|
|
|
/// </summary>
|
|
|
|
/// <value>
|
|
|
|
/// The shutdown mode.
|
|
|
|
/// </value>
|
|
|
|
public ExitMode ExitMode { get; set; } |
|
|
|
public ShutdownMode ShutdownMode { get; set; } |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Gets or sets the main window of the application.
|
|
|
|
@ -190,108 +194,171 @@ namespace Avalonia |
|
|
|
public WindowCollection Windows { get; } |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Gets or sets a value indicating whether this instance is existing.
|
|
|
|
/// Gets or sets a value indicating whether this instance is shutting down.
|
|
|
|
/// </summary>
|
|
|
|
/// <value>
|
|
|
|
/// <c>true</c> if this instance is existing; otherwise, <c>false</c>.
|
|
|
|
/// <c>true</c> if this instance is shutting down; otherwise, <c>false</c>.
|
|
|
|
/// </value>
|
|
|
|
internal bool IsExiting { get; set; } |
|
|
|
internal bool IsShuttingDown { get; private set; } |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Initializes the application by loading XAML etc.
|
|
|
|
/// </summary>
|
|
|
|
public virtual void Initialize() |
|
|
|
public virtual void Initialize() { } |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Runs the application's main loop.
|
|
|
|
/// </summary>
|
|
|
|
/// <remarks>
|
|
|
|
/// This will return when the <see cref="Avalonia.Controls.ShutdownMode"/> condition is met
|
|
|
|
/// or <see cref="Shutdown(int)"/> was called.
|
|
|
|
/// </remarks>
|
|
|
|
/// <returns>The application's exit code that is returned to the operating system on termination.</returns>
|
|
|
|
public int Run() |
|
|
|
{ |
|
|
|
return Run(new CancellationTokenSource()); |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Runs the application's main loop until the <see cref="ICloseable"/> is closed.
|
|
|
|
/// Runs the application's main loop.
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="closable">The closable to track</param>
|
|
|
|
public void Run(ICloseable closable) |
|
|
|
/// <remarks>
|
|
|
|
/// This will return when the <see cref="Avalonia.Controls.ShutdownMode"/> condition is met
|
|
|
|
/// or <see cref="Shutdown(int)"/> was called.
|
|
|
|
/// This also returns when <see cref="ICloseable"/> is closed.
|
|
|
|
/// </remarks>
|
|
|
|
/// <param name="closable">The closable to track.</param>
|
|
|
|
/// <returns>The application's exit code that is returned to the operating system on termination.</returns>
|
|
|
|
public int Run(ICloseable closable) |
|
|
|
{ |
|
|
|
if (_mainLoopCancellationTokenSource != null) |
|
|
|
closable.Closed += (s, e) => _mainLoopCancellationTokenSource?.Cancel(); |
|
|
|
|
|
|
|
return Run(new CancellationTokenSource()); |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Runs the application's main loop.
|
|
|
|
/// </summary>
|
|
|
|
/// <remarks>
|
|
|
|
/// This will return when the <see cref="Avalonia.Controls.ShutdownMode"/> condition is met
|
|
|
|
/// or <see cref="Shutdown(int)"/> was called.
|
|
|
|
/// </remarks>
|
|
|
|
/// <param name="mainWindow">The window that is used as <see cref="MainWindow"/>
|
|
|
|
/// when the <see cref="MainWindow"/> isn't already set.</param>
|
|
|
|
/// <returns>The application's exit code that is returned to the operating system on termination.</returns>
|
|
|
|
public int Run(Window mainWindow) |
|
|
|
{ |
|
|
|
if (mainWindow == null) |
|
|
|
{ |
|
|
|
throw new Exception("Run should only called once"); |
|
|
|
throw new ArgumentNullException(nameof(mainWindow)); |
|
|
|
} |
|
|
|
|
|
|
|
closable.Closed += (s, e) => Exit(); |
|
|
|
|
|
|
|
_mainLoopCancellationTokenSource = new CancellationTokenSource(); |
|
|
|
if (MainWindow == null) |
|
|
|
{ |
|
|
|
Dispatcher.UIThread.Post(() => |
|
|
|
{ |
|
|
|
if (!mainWindow.IsVisible) |
|
|
|
{ |
|
|
|
mainWindow.Show(); |
|
|
|
} |
|
|
|
|
|
|
|
Dispatcher.UIThread.MainLoop(_mainLoopCancellationTokenSource.Token); |
|
|
|
MainWindow = mainWindow; |
|
|
|
}); |
|
|
|
} |
|
|
|
|
|
|
|
// Make sure we call OnExit in case an error happened and Exit() wasn't called explicitly
|
|
|
|
if (!IsExiting) |
|
|
|
{ |
|
|
|
OnExit?.Invoke(this, EventArgs.Empty); |
|
|
|
} |
|
|
|
return Run(new CancellationTokenSource()); |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Runs the application's main loop until some condition occurs that is specified by ExitMode.
|
|
|
|
/// Runs the application's main loop.
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="mainWindow">The main window</param>
|
|
|
|
public void Run(Window mainWindow) |
|
|
|
/// <remarks>
|
|
|
|
/// This will return when the <see cref="Avalonia.Controls.ShutdownMode"/> condition is met
|
|
|
|
/// or <see cref="Shutdown(int)"/> was called.
|
|
|
|
/// This also returns when the <see cref="CancellationToken"/> is canceled.
|
|
|
|
/// </remarks>
|
|
|
|
/// <returns>The application's exit code that is returned to the operating system on termination.</returns>
|
|
|
|
/// <param name="token">The token to track.</param>
|
|
|
|
public int Run(CancellationToken token) |
|
|
|
{ |
|
|
|
if (_mainLoopCancellationTokenSource != null) |
|
|
|
return Run(CancellationTokenSource.CreateLinkedTokenSource(token)); |
|
|
|
} |
|
|
|
|
|
|
|
private int Run(CancellationTokenSource tokenSource) |
|
|
|
{ |
|
|
|
if (IsShuttingDown) |
|
|
|
{ |
|
|
|
throw new Exception("Run should only called once"); |
|
|
|
throw new InvalidOperationException("Application is shutting down."); |
|
|
|
} |
|
|
|
|
|
|
|
_mainLoopCancellationTokenSource = new CancellationTokenSource(); |
|
|
|
|
|
|
|
if (MainWindow == null) |
|
|
|
if (_mainLoopCancellationTokenSource != null) |
|
|
|
{ |
|
|
|
if (mainWindow == null) |
|
|
|
{ |
|
|
|
throw new ArgumentNullException(nameof(mainWindow)); |
|
|
|
} |
|
|
|
throw new InvalidOperationException("Application is already running."); |
|
|
|
} |
|
|
|
|
|
|
|
if (!mainWindow.IsVisible) |
|
|
|
{ |
|
|
|
mainWindow.Show(); |
|
|
|
} |
|
|
|
_mainLoopCancellationTokenSource = tokenSource; |
|
|
|
|
|
|
|
MainWindow = mainWindow; |
|
|
|
} |
|
|
|
Dispatcher.UIThread.Post(() => OnStartup(new StartupEventArgs()), DispatcherPriority.Send); |
|
|
|
|
|
|
|
Dispatcher.UIThread.MainLoop(_mainLoopCancellationTokenSource.Token); |
|
|
|
|
|
|
|
// Make sure we call OnExit in case an error happened and Exit() wasn't called explicitly
|
|
|
|
if (!IsExiting) |
|
|
|
if (!IsShuttingDown) |
|
|
|
{ |
|
|
|
OnExit?.Invoke(this, EventArgs.Empty); |
|
|
|
Shutdown(_exitCode); |
|
|
|
} |
|
|
|
|
|
|
|
return _exitCode; |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Runs the application's main loop until the <see cref="CancellationToken"/> is canceled.
|
|
|
|
/// Raises the <see cref="Startup"/> event.
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="token">The token to track</param>
|
|
|
|
public void Run(CancellationToken token) |
|
|
|
/// <param name="e">A <see cref="StartupEventArgs"/> that contains the event data.</param>
|
|
|
|
protected virtual void OnStartup(StartupEventArgs e) |
|
|
|
{ |
|
|
|
Dispatcher.UIThread.MainLoop(token); |
|
|
|
|
|
|
|
// Make sure we call OnExit in case an error happened and Exit() wasn't called explicitly
|
|
|
|
if (!IsExiting) |
|
|
|
{ |
|
|
|
OnExit?.Invoke(this, EventArgs.Empty); |
|
|
|
} |
|
|
|
Startup?.Invoke(this, e); |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Exits the application
|
|
|
|
/// Raises the <see cref="Exit"/> event.
|
|
|
|
/// </summary>
|
|
|
|
public void Exit() |
|
|
|
/// <param name="e">A <see cref="ExitEventArgs"/> that contains the event data.</param>
|
|
|
|
protected virtual void OnExit(ExitEventArgs e) |
|
|
|
{ |
|
|
|
IsExiting = true; |
|
|
|
Exit?.Invoke(this, e); |
|
|
|
} |
|
|
|
|
|
|
|
/// <inheritdoc/>
|
|
|
|
public void Shutdown(int exitCode = 0) |
|
|
|
{ |
|
|
|
if (IsShuttingDown) |
|
|
|
{ |
|
|
|
throw new InvalidOperationException("Application is already shutting down."); |
|
|
|
} |
|
|
|
|
|
|
|
_exitCode = exitCode; |
|
|
|
|
|
|
|
IsShuttingDown = true; |
|
|
|
|
|
|
|
Windows.Clear(); |
|
|
|
|
|
|
|
OnExit?.Invoke(this, EventArgs.Empty); |
|
|
|
try |
|
|
|
{ |
|
|
|
var e = new ExitEventArgs { ApplicationExitCode = _exitCode }; |
|
|
|
|
|
|
|
OnExit(e); |
|
|
|
|
|
|
|
_exitCode = e.ApplicationExitCode; |
|
|
|
} |
|
|
|
finally |
|
|
|
{ |
|
|
|
_mainLoopCancellationTokenSource?.Cancel(); |
|
|
|
|
|
|
|
_mainLoopCancellationTokenSource = null; |
|
|
|
|
|
|
|
IsShuttingDown = false; |
|
|
|
|
|
|
|
_mainLoopCancellationTokenSource?.Cancel(); |
|
|
|
Environment.ExitCode = _exitCode; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/// <inheritdoc/>
|
|
|
|
@ -302,20 +369,6 @@ namespace Avalonia |
|
|
|
Styles.TryGetResource(key, out value); |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Sent when the application is exiting.
|
|
|
|
/// </summary>
|
|
|
|
public event EventHandler OnExit; |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Called when the application is exiting.
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="sender"></param>
|
|
|
|
/// <param name="e"></param>
|
|
|
|
protected virtual void OnExiting(object sender, EventArgs e) |
|
|
|
{ |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Register's the services needed by Avalonia.
|
|
|
|
/// </summary>
|
|
|
|
|