From 21eda0db12c13b27a0671ec2df8b04c9011c461d Mon Sep 17 00:00:00 2001 From: Benedikt Schroeder Date: Sat, 20 Apr 2019 18:36:51 +0200 Subject: [PATCH] Revert removal of Application.Initialize --- samples/BindingDemo/App.xaml.cs | 2 +- samples/ControlCatalog.NetCore/Program.cs | 2 +- samples/ControlCatalog/App.xaml.cs | 11 +- samples/PlatformSanityChecks/App.xaml.cs | 2 +- samples/Previewer/App.xaml.cs | 2 +- samples/RenderDemo/App.xaml.cs | 2 +- samples/VirtualizationDemo/App.xaml.cs | 2 +- .../interop/Direct3DInteropSample/App.paml.cs | 2 +- src/Avalonia.Controls/AppBuilderBase.cs | 1 + src/Avalonia.Controls/Application.cs | 104 +++++++++++------- .../Controls/ExitEventArgs.cs | 6 +- .../ApplicationTests.cs | 25 +++++ .../App.xaml.cs | 2 +- 13 files changed, 102 insertions(+), 61 deletions(-) diff --git a/samples/BindingDemo/App.xaml.cs b/samples/BindingDemo/App.xaml.cs index 88333857b8..f2f44cd502 100644 --- a/samples/BindingDemo/App.xaml.cs +++ b/samples/BindingDemo/App.xaml.cs @@ -10,7 +10,7 @@ namespace BindingDemo { public class App : Application { - protected override void OnStartup(StartupEventArgs e) + public override void Initialize() { AvaloniaXamlLoader.Load(this); } diff --git a/samples/ControlCatalog.NetCore/Program.cs b/samples/ControlCatalog.NetCore/Program.cs index 24f88ecba0..6a8175129f 100644 --- a/samples/ControlCatalog.NetCore/Program.cs +++ b/samples/ControlCatalog.NetCore/Program.cs @@ -31,7 +31,7 @@ namespace ControlCatalog.NetCore ThreadPool.QueueUserWorkItem(_ => ConsoleSilencer()); }); else - BuildAvaloniaApp().Start(); + BuildAvaloniaApp().Start(); } /// diff --git a/samples/ControlCatalog/App.xaml.cs b/samples/ControlCatalog/App.xaml.cs index 100cfa634e..d862749132 100644 --- a/samples/ControlCatalog/App.xaml.cs +++ b/samples/ControlCatalog/App.xaml.cs @@ -1,22 +1,13 @@ using Avalonia; -using Avalonia.Controls; using Avalonia.Markup.Xaml; namespace ControlCatalog { public class App : Application { - protected override void OnStartup(StartupEventArgs e) + public override void Initialize() { - base.OnStartup(e); - AvaloniaXamlLoader.Load(this); - - var mainWindow = new MainWindow(); - - mainWindow.Show(); - - MainWindow = mainWindow; } } } diff --git a/samples/PlatformSanityChecks/App.xaml.cs b/samples/PlatformSanityChecks/App.xaml.cs index b8f8350156..0f9c004630 100644 --- a/samples/PlatformSanityChecks/App.xaml.cs +++ b/samples/PlatformSanityChecks/App.xaml.cs @@ -6,7 +6,7 @@ namespace PlatformSanityChecks { public class App : Application { - protected override void OnStartup(StartupEventArgs e) + public override void Initialize() { AvaloniaXamlLoader.Load(this); } diff --git a/samples/Previewer/App.xaml.cs b/samples/Previewer/App.xaml.cs index 0fc42583a5..6d7d051218 100644 --- a/samples/Previewer/App.xaml.cs +++ b/samples/Previewer/App.xaml.cs @@ -6,7 +6,7 @@ namespace Previewer { public class App : Application { - protected override void OnStartup(StartupEventArgs e) + public override void Initialize() { AvaloniaXamlLoader.Load(this); } diff --git a/samples/RenderDemo/App.xaml.cs b/samples/RenderDemo/App.xaml.cs index b758f887df..ce75a335d5 100644 --- a/samples/RenderDemo/App.xaml.cs +++ b/samples/RenderDemo/App.xaml.cs @@ -11,7 +11,7 @@ namespace RenderDemo { public class App : Application { - protected override void OnStartup(StartupEventArgs e) + public override void Initialize() { AvaloniaXamlLoader.Load(this); } diff --git a/samples/VirtualizationDemo/App.xaml.cs b/samples/VirtualizationDemo/App.xaml.cs index 787bbf8d11..637c8726f6 100644 --- a/samples/VirtualizationDemo/App.xaml.cs +++ b/samples/VirtualizationDemo/App.xaml.cs @@ -9,7 +9,7 @@ namespace VirtualizationDemo { public class App : Application { - protected override void OnStartup(StartupEventArgs e) + public override void Initialize() { AvaloniaXamlLoader.Load(this); } diff --git a/samples/interop/Direct3DInteropSample/App.paml.cs b/samples/interop/Direct3DInteropSample/App.paml.cs index b08c02509c..5269854138 100644 --- a/samples/interop/Direct3DInteropSample/App.paml.cs +++ b/samples/interop/Direct3DInteropSample/App.paml.cs @@ -6,7 +6,7 @@ namespace Direct3DInteropSample { public class App : Application { - protected override void OnStartup(StartupEventArgs e) + public override void Initialize() { AvaloniaXamlLoader.Load(this); } diff --git a/src/Avalonia.Controls/AppBuilderBase.cs b/src/Avalonia.Controls/AppBuilderBase.cs index 697c838b6a..419064b051 100644 --- a/src/Avalonia.Controls/AppBuilderBase.cs +++ b/src/Avalonia.Controls/AppBuilderBase.cs @@ -311,6 +311,7 @@ namespace Avalonia.Controls WindowingSubsystemInitializer(); RenderingSubsystemInitializer(); Instance.RegisterServices(); + Instance.Initialize(); AfterSetupCallback(Self); } } diff --git a/src/Avalonia.Controls/Application.cs b/src/Avalonia.Controls/Application.cs index 99fc2e7367..e0f7b84e98 100644 --- a/src/Avalonia.Controls/Application.cs +++ b/src/Avalonia.Controls/Application.cs @@ -43,8 +43,8 @@ namespace Avalonia private readonly Styler _styler = new Styler(); private Styles _styles; private IResourceDictionary _resources; - private CancellationTokenSource _mainLoopCancellationTokenSource; + private int _exitCode; /// /// Initializes a new instance of the class. @@ -201,53 +201,40 @@ namespace Avalonia /// internal bool IsShuttingDown { get; private set; } - public void Run() - { - if (_mainLoopCancellationTokenSource != null) - { - throw new Exception("Run should only called once"); - } - - _mainLoopCancellationTokenSource = new CancellationTokenSource(); - - Dispatcher.UIThread.Post(() => OnStartup(new StartupEventArgs()), DispatcherPriority.Send); + /// + /// Initializes the application by loading XAML etc. + /// + public virtual void Initialize() { } - Run(_mainLoopCancellationTokenSource.Token); + public int Run() + { + return Run(new CancellationTokenSource()); } /// /// Runs the application's main loop until the is closed. /// /// The closable to track - public void Run(ICloseable closable) + public int Run(ICloseable closable) { - if (_mainLoopCancellationTokenSource != null) - { - throw new Exception("Run should only called once"); - } - - _mainLoopCancellationTokenSource = new CancellationTokenSource(); - closable.Closed += (s, e) => _mainLoopCancellationTokenSource?.Cancel(); - Run(_mainLoopCancellationTokenSource.Token); + return Run(new CancellationTokenSource()); } /// /// Runs the application's main loop until some condition occurs that is specified by ExitMode. /// /// The main window - public void Run(Window mainWindow) + public int Run(Window mainWindow) { - if (_mainLoopCancellationTokenSource != null) + Dispatcher.UIThread.Post(() => { - throw new Exception("Run should only called once"); - } - - _mainLoopCancellationTokenSource = new CancellationTokenSource(); + if (MainWindow != null) + { + return; + } - if (MainWindow == null) - { if (mainWindow == null) { throw new ArgumentNullException(nameof(mainWindow)); @@ -259,20 +246,44 @@ namespace Avalonia } MainWindow = mainWindow; - } + }); - Run(_mainLoopCancellationTokenSource.Token); + return Run(new CancellationTokenSource()); } /// /// Runs the application's main loop until the is canceled. /// /// The token to track - public void Run(CancellationToken token) + public int Run(CancellationToken token) { - Dispatcher.UIThread.MainLoop(token); + return Run(CancellationTokenSource.CreateLinkedTokenSource(token)); + } - Shutdown(); + private int Run(CancellationTokenSource tokenSource) + { + if (IsShuttingDown) + { + throw new InvalidOperationException("Application is shutting down."); + } + + if (_mainLoopCancellationTokenSource != null) + { + throw new InvalidOperationException("Application is already running."); + } + + _mainLoopCancellationTokenSource = tokenSource; + + Dispatcher.UIThread.Post(() => OnStartup(new StartupEventArgs()), DispatcherPriority.Send); + + Dispatcher.UIThread.MainLoop(_mainLoopCancellationTokenSource.Token); + + if (!IsShuttingDown) + { + Shutdown(_exitCode); + } + + return _exitCode; } protected virtual void OnStartup(StartupEventArgs e) @@ -296,16 +307,33 @@ namespace Avalonia { if (IsShuttingDown) { - return; + throw new InvalidOperationException("Application is already shutting down."); } - IsShuttingDown = true; + _exitCode = exitCode; + + IsShuttingDown = true; Windows.Clear(); - OnExit(new ExitEventArgs { ApplicationExitCode = exitCode }); + try + { + var e = new ExitEventArgs { ApplicationExitCode = _exitCode }; + + OnExit(e); - _mainLoopCancellationTokenSource?.Cancel(); + _exitCode = e.ApplicationExitCode; + + Environment.ExitCode = _exitCode; + } + finally + { + _mainLoopCancellationTokenSource?.Cancel(); + + _mainLoopCancellationTokenSource = null; + + IsShuttingDown = false; + } } /// diff --git a/src/Avalonia.Styling/Controls/ExitEventArgs.cs b/src/Avalonia.Styling/Controls/ExitEventArgs.cs index 2e6409e296..1a4ee15f17 100644 --- a/src/Avalonia.Styling/Controls/ExitEventArgs.cs +++ b/src/Avalonia.Styling/Controls/ExitEventArgs.cs @@ -7,10 +7,6 @@ namespace Avalonia.Controls { public class ExitEventArgs : EventArgs { - public int ApplicationExitCode - { - get => Environment.ExitCode; - set => Environment.ExitCode = value; - } + public int ApplicationExitCode { get; set; } } } diff --git a/tests/Avalonia.Controls.UnitTests/ApplicationTests.cs b/tests/Avalonia.Controls.UnitTests/ApplicationTests.cs index f362e691dc..f9b1ea251b 100644 --- a/tests/Avalonia.Controls.UnitTests/ApplicationTests.cs +++ b/tests/Avalonia.Controls.UnitTests/ApplicationTests.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using Avalonia.Threading; using Avalonia.UnitTests; using Xunit; @@ -129,5 +130,29 @@ namespace Avalonia.Controls.UnitTests Assert.True(raised); } } + + [Fact] + public void Throws_InvalidOperationException_On_Run_When_Application_Is_Already_Running() + { + using (UnitTestApplication.Start(TestServices.MockThreadingInterface)) + { + Application.Current.Run(); + + Assert.Throws(() => { Application.Current.Run(); }); + } + } + + [Fact] + public void Should_Set_ExitCode_After_Shutdown() + { + using (UnitTestApplication.Start(TestServices.MockThreadingInterface)) + { + Application.Current.Shutdown(1337); + + var exitCode = Application.Current.Run(); + + Assert.Equal(1337, exitCode); + } + } } } diff --git a/tests/Avalonia.DesignerSupport.TestApp/App.xaml.cs b/tests/Avalonia.DesignerSupport.TestApp/App.xaml.cs index e2fc6ab7a2..caa3c1baa8 100644 --- a/tests/Avalonia.DesignerSupport.TestApp/App.xaml.cs +++ b/tests/Avalonia.DesignerSupport.TestApp/App.xaml.cs @@ -5,7 +5,7 @@ namespace Avalonia.DesignerSupport.TestApp { public class App : Application { - protected override void OnStartup(StartupEventArgs e) + public override void Initialize() { AvaloniaXamlLoader.Load(this); }