committed by
GitHub
27 changed files with 615 additions and 767 deletions
@ -0,0 +1,133 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Linq; |
||||
|
using System.Threading; |
||||
|
using Avalonia.Controls; |
||||
|
using Avalonia.Controls.ApplicationLifetimes; |
||||
|
using Avalonia.Interactivity; |
||||
|
|
||||
|
namespace Avalonia.Controls.ApplicationLifetimes |
||||
|
{ |
||||
|
public class ClassicDesktopStyleApplicationLifetime : IClassicDesktopStyleApplicationLifetime, IDisposable |
||||
|
{ |
||||
|
private readonly Application _app; |
||||
|
private int _exitCode; |
||||
|
private CancellationTokenSource _cts; |
||||
|
private bool _isShuttingDown; |
||||
|
private HashSet<Window> _windows = new HashSet<Window>(); |
||||
|
|
||||
|
private static ClassicDesktopStyleApplicationLifetime _activeLifetime; |
||||
|
static ClassicDesktopStyleApplicationLifetime() |
||||
|
{ |
||||
|
Window.WindowOpenedEvent.AddClassHandler(typeof(Window), OnWindowOpened); |
||||
|
Window.WindowClosedEvent.AddClassHandler(typeof(Window), WindowClosedEvent); |
||||
|
} |
||||
|
|
||||
|
private static void WindowClosedEvent(object sender, RoutedEventArgs e) |
||||
|
{ |
||||
|
_activeLifetime?._windows.Remove((Window)sender); |
||||
|
_activeLifetime?.HandleWindowClosed((Window)sender); |
||||
|
} |
||||
|
|
||||
|
private static void OnWindowOpened(object sender, RoutedEventArgs e) |
||||
|
{ |
||||
|
_activeLifetime?._windows.Add((Window)sender); |
||||
|
} |
||||
|
|
||||
|
public ClassicDesktopStyleApplicationLifetime(Application app) |
||||
|
{ |
||||
|
if (_activeLifetime != null) |
||||
|
throw new InvalidOperationException( |
||||
|
"Can not have multiple active ClassicDesktopStyleApplicationLifetime instances and the previously created one was not disposed"); |
||||
|
_app = app; |
||||
|
_activeLifetime = this; |
||||
|
} |
||||
|
|
||||
|
/// <inheritdoc/>
|
||||
|
public event EventHandler<ControlledApplicationLifetimeStartupEventArgs> Startup; |
||||
|
/// <inheritdoc/>
|
||||
|
public event EventHandler<ControlledApplicationLifetimeExitEventArgs> Exit; |
||||
|
|
||||
|
/// <inheritdoc/>
|
||||
|
public ShutdownMode ShutdownMode { get; set; } |
||||
|
|
||||
|
/// <inheritdoc/>
|
||||
|
public Window MainWindow { get; set; } |
||||
|
|
||||
|
public IReadOnlyList<Window> Windows => _windows.ToList(); |
||||
|
|
||||
|
private void HandleWindowClosed(Window window) |
||||
|
{ |
||||
|
if (window == null) |
||||
|
return; |
||||
|
|
||||
|
if (_isShuttingDown) |
||||
|
return; |
||||
|
|
||||
|
if (ShutdownMode == ShutdownMode.OnLastWindowClose && _windows.Count == 0) |
||||
|
Shutdown(); |
||||
|
else if (ShutdownMode == ShutdownMode.OnMainWindowClose && window == MainWindow) |
||||
|
Shutdown(); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
public void Shutdown(int exitCode = 0) |
||||
|
{ |
||||
|
if (_isShuttingDown) |
||||
|
throw new InvalidOperationException("Application is already shutting down."); |
||||
|
|
||||
|
_exitCode = exitCode; |
||||
|
_isShuttingDown = true; |
||||
|
|
||||
|
try |
||||
|
{ |
||||
|
foreach (var w in Windows) |
||||
|
w.Close(); |
||||
|
var e = new ControlledApplicationLifetimeExitEventArgs(exitCode); |
||||
|
Exit?.Invoke(this, e); |
||||
|
_exitCode = e.ApplicationExitCode; |
||||
|
} |
||||
|
finally |
||||
|
{ |
||||
|
_cts?.Cancel(); |
||||
|
_cts = null; |
||||
|
_isShuttingDown = false; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
|
||||
|
public int Start(string[] args) |
||||
|
{ |
||||
|
Startup?.Invoke(this, new ControlledApplicationLifetimeStartupEventArgs(args)); |
||||
|
_cts = new CancellationTokenSource(); |
||||
|
MainWindow?.Show(); |
||||
|
_app.Run(_cts.Token); |
||||
|
Environment.ExitCode = _exitCode; |
||||
|
return _exitCode; |
||||
|
} |
||||
|
|
||||
|
public void Dispose() |
||||
|
{ |
||||
|
if (_activeLifetime == this) |
||||
|
_activeLifetime = null; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
namespace Avalonia |
||||
|
{ |
||||
|
public static class ClassicDesktopStyleApplicationLifetimeExtensions |
||||
|
{ |
||||
|
public static int StartWithClassicDesktopLifetime<T>( |
||||
|
this T builder, string[] args, ShutdownMode shutdownMode = ShutdownMode.OnLastWindowClose) |
||||
|
where T : AppBuilderBase<T>, new() |
||||
|
{ |
||||
|
var lifetime = new ClassicDesktopStyleApplicationLifetime(builder.Instance) {ShutdownMode = shutdownMode}; |
||||
|
builder.Instance.ApplicationLifetime = lifetime; |
||||
|
builder.SetupWithoutStarting(); |
||||
|
return lifetime.Start(args); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,7 @@ |
|||||
|
namespace Avalonia.Controls.ApplicationLifetimes |
||||
|
{ |
||||
|
public interface IApplicationLifetime |
||||
|
{ |
||||
|
|
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,31 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
|
||||
|
namespace Avalonia.Controls.ApplicationLifetimes |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Controls application lifetime in classic desktop style
|
||||
|
/// </summary>
|
||||
|
public interface IClassicDesktopStyleApplicationLifetime : IControlledApplicationLifetime |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 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>
|
||||
|
ShutdownMode ShutdownMode { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets or sets the main window of the application.
|
||||
|
/// </summary>
|
||||
|
/// <value>
|
||||
|
/// The main window.
|
||||
|
/// </value>
|
||||
|
Window MainWindow { get; set; } |
||||
|
|
||||
|
IReadOnlyList<Window> Windows { get; } |
||||
|
} |
||||
|
} |
||||
@ -1,22 +1,19 @@ |
|||||
using System; |
using System; |
||||
|
|
||||
namespace Avalonia.Controls |
namespace Avalonia.Controls.ApplicationLifetimes |
||||
{ |
{ |
||||
/// <summary>
|
public interface IControlledApplicationLifetime : IApplicationLifetime |
||||
/// Sends events about the application lifecycle.
|
|
||||
/// </summary>
|
|
||||
public interface IApplicationLifecycle |
|
||||
{ |
{ |
||||
/// <summary>
|
/// <summary>
|
||||
/// Sent when the application is starting up.
|
/// Sent when the application is starting up.
|
||||
/// </summary>
|
/// </summary>
|
||||
event EventHandler<StartupEventArgs> Startup; |
event EventHandler<ControlledApplicationLifetimeStartupEventArgs> Startup; |
||||
|
|
||||
/// <summary>
|
/// <summary>
|
||||
/// Sent when the application is exiting.
|
/// Sent when the application is exiting.
|
||||
/// </summary>
|
/// </summary>
|
||||
event EventHandler<ExitEventArgs> Exit; |
event EventHandler<ControlledApplicationLifetimeExitEventArgs> Exit; |
||||
|
|
||||
/// <summary>
|
/// <summary>
|
||||
/// Shuts down the application and sets the exit code that is returned to the operating system when the application exits.
|
/// Shuts down the application and sets the exit code that is returned to the operating system when the application exits.
|
||||
/// </summary>
|
/// </summary>
|
||||
@ -0,0 +1,7 @@ |
|||||
|
namespace Avalonia.Controls.ApplicationLifetimes |
||||
|
{ |
||||
|
public interface ISingleViewApplicationLifetime : IApplicationLifetime |
||||
|
{ |
||||
|
Control MainView { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,22 @@ |
|||||
|
// Copyright (c) The Avalonia Project. All rights reserved.
|
||||
|
// Licensed under the MIT license. See licence.md file in the project root for full license information.
|
||||
|
|
||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Linq; |
||||
|
|
||||
|
namespace Avalonia.Controls.ApplicationLifetimes |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Contains the arguments for the <see cref="IClassicDesktopStyleApplicationLifetime.Startup"/> event.
|
||||
|
/// </summary>
|
||||
|
public class ControlledApplicationLifetimeStartupEventArgs : EventArgs |
||||
|
{ |
||||
|
public ControlledApplicationLifetimeStartupEventArgs(IEnumerable<string> args) |
||||
|
{ |
||||
|
Args = args?.ToArray() ?? Array.Empty<string>(); |
||||
|
} |
||||
|
|
||||
|
public string[] Args { get; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,67 @@ |
|||||
|
using System; |
||||
|
using System.Threading; |
||||
|
using Avalonia.Controls; |
||||
|
using Avalonia.Input; |
||||
|
using Avalonia.Threading; |
||||
|
|
||||
|
namespace Avalonia.Controls |
||||
|
{ |
||||
|
public static class DesktopApplicationExtensions |
||||
|
{ |
||||
|
[Obsolete("Running application without a cancellation token and a lifetime is no longer supported, see https://github.com/AvaloniaUI/Avalonia/wiki/Application-lifetimes for details")] |
||||
|
public static void Run(this Application app) => throw new NotSupportedException(); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// On desktop-style platforms runs the application's main loop until closable is closed
|
||||
|
/// </summary>
|
||||
|
/// <remarks>
|
||||
|
/// Consider using StartWithDesktopStyleLifetime instead, see https://github.com/AvaloniaUI/Avalonia/wiki/Application-lifetimes for details
|
||||
|
/// </remarks>
|
||||
|
public static void Run(this Application app, ICloseable closable) |
||||
|
{ |
||||
|
var cts = new CancellationTokenSource(); |
||||
|
closable.Closed += (s, e) => cts.Cancel(); |
||||
|
|
||||
|
app.Run(cts.Token); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// On desktop-style platforms runs the application's main loop until main window is closed
|
||||
|
/// </summary>
|
||||
|
/// <remarks>
|
||||
|
/// Consider using StartWithDesktopStyleLifetime instead, see https://github.com/AvaloniaUI/Avalonia/wiki/Application-lifetimes for details
|
||||
|
/// </remarks>
|
||||
|
public static void Run(this Application app, Window mainWindow) |
||||
|
{ |
||||
|
if (mainWindow == null) |
||||
|
{ |
||||
|
throw new ArgumentNullException(nameof(mainWindow)); |
||||
|
} |
||||
|
var cts = new CancellationTokenSource(); |
||||
|
mainWindow.Closed += (_, __) => cts.Cancel(); |
||||
|
if (!mainWindow.IsVisible) |
||||
|
{ |
||||
|
mainWindow.Show(); |
||||
|
} |
||||
|
app.Run(cts.Token); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// On desktop-style platforms runs the application's main loop with custom CancellationToken
|
||||
|
/// without setting a lifetime.
|
||||
|
/// </summary>
|
||||
|
/// <param name="token">The token to track.</param>
|
||||
|
public static void Run(this Application app, CancellationToken token) |
||||
|
{ |
||||
|
Dispatcher.UIThread.MainLoop(token); |
||||
|
} |
||||
|
|
||||
|
public static void RunWithMainWindow<TWindow>(this Application app) |
||||
|
where TWindow : Avalonia.Controls.Window, new() |
||||
|
{ |
||||
|
var window = new TWindow(); |
||||
|
window.Show(); |
||||
|
app.Run(window); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -1,36 +0,0 @@ |
|||||
// Copyright (c) The Avalonia Project. All rights reserved.
|
|
||||
// Licensed under the MIT license. See licence.md file in the project root for full license information.
|
|
||||
|
|
||||
using System; |
|
||||
using System.Collections.Generic; |
|
||||
using System.Linq; |
|
||||
|
|
||||
namespace Avalonia.Controls |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Contains the arguments for the <see cref="IApplicationLifecycle.Startup"/> event.
|
|
||||
/// </summary>
|
|
||||
public class StartupEventArgs : EventArgs |
|
||||
{ |
|
||||
private string[] _args; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets the command line arguments that were passed to the application.
|
|
||||
/// </summary>
|
|
||||
public IReadOnlyList<string> Args => _args ?? (_args = GetArgs()); |
|
||||
|
|
||||
private static string[] GetArgs() |
|
||||
{ |
|
||||
try |
|
||||
{ |
|
||||
var args = Environment.GetCommandLineArgs(); |
|
||||
|
|
||||
return args.Length > 1 ? args.Skip(1).ToArray() : new string[0]; |
|
||||
} |
|
||||
catch (NotSupportedException) |
|
||||
{ |
|
||||
return new string[0]; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,134 +0,0 @@ |
|||||
// Copyright (c) The Avalonia Project. All rights reserved.
|
|
||||
// Licensed under the MIT license. See licence.md file in the project root for full license information.
|
|
||||
|
|
||||
using System.Collections; |
|
||||
using System.Collections.Generic; |
|
||||
|
|
||||
using Avalonia.Controls; |
|
||||
|
|
||||
namespace Avalonia |
|
||||
{ |
|
||||
public class WindowCollection : IReadOnlyList<Window> |
|
||||
{ |
|
||||
private readonly Application _application; |
|
||||
private readonly List<Window> _windows = new List<Window>(); |
|
||||
|
|
||||
public WindowCollection(Application application) |
|
||||
{ |
|
||||
_application = application; |
|
||||
} |
|
||||
|
|
||||
/// <inheritdoc />
|
|
||||
/// <summary>
|
|
||||
/// Gets the number of elements in the collection.
|
|
||||
/// </summary>
|
|
||||
public int Count => _windows.Count; |
|
||||
|
|
||||
/// <inheritdoc />
|
|
||||
/// <summary>
|
|
||||
/// Gets the <see cref="T:Avalonia.Controls.Window" /> at the specified index.
|
|
||||
/// </summary>
|
|
||||
/// <value>
|
|
||||
/// The <see cref="T:Avalonia.Controls.Window" />.
|
|
||||
/// </value>
|
|
||||
/// <param name="index">The index.</param>
|
|
||||
/// <returns></returns>
|
|
||||
public Window this[int index] => _windows[index]; |
|
||||
|
|
||||
/// <inheritdoc />
|
|
||||
/// <summary>
|
|
||||
/// Returns an enumerator that iterates through the collection.
|
|
||||
/// </summary>
|
|
||||
/// <returns>
|
|
||||
/// An enumerator that can be used to iterate through the collection.
|
|
||||
/// </returns>
|
|
||||
public IEnumerator<Window> GetEnumerator() |
|
||||
{ |
|
||||
return _windows.GetEnumerator(); |
|
||||
} |
|
||||
|
|
||||
/// <inheritdoc />
|
|
||||
/// <summary>
|
|
||||
/// Returns an enumerator that iterates through a collection.
|
|
||||
/// </summary>
|
|
||||
/// <returns>
|
|
||||
/// An <see cref="T:System.Collections.IEnumerator"></see> object that can be used to iterate through the collection.
|
|
||||
/// </returns>
|
|
||||
IEnumerator IEnumerable.GetEnumerator() |
|
||||
{ |
|
||||
return GetEnumerator(); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Adds the specified window.
|
|
||||
/// </summary>
|
|
||||
/// <param name="window">The window.</param>
|
|
||||
internal void Add(Window window) |
|
||||
{ |
|
||||
if (window == null) |
|
||||
{ |
|
||||
return; |
|
||||
} |
|
||||
|
|
||||
_windows.Add(window); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Removes the specified window.
|
|
||||
/// </summary>
|
|
||||
/// <param name="window">The window.</param>
|
|
||||
internal void Remove(Window window) |
|
||||
{ |
|
||||
if (window == null) |
|
||||
{ |
|
||||
return; |
|
||||
} |
|
||||
|
|
||||
_windows.Remove(window); |
|
||||
|
|
||||
OnRemoveWindow(window); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Closes all windows and removes them from the underlying collection.
|
|
||||
/// </summary>
|
|
||||
internal void Clear() |
|
||||
{ |
|
||||
while (_windows.Count > 0) |
|
||||
{ |
|
||||
_windows[0].Close(true); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
private void OnRemoveWindow(Window window) |
|
||||
{ |
|
||||
if (window == null) |
|
||||
{ |
|
||||
return; |
|
||||
} |
|
||||
|
|
||||
if (_application.IsShuttingDown) |
|
||||
{ |
|
||||
return; |
|
||||
} |
|
||||
|
|
||||
switch (_application.ShutdownMode) |
|
||||
{ |
|
||||
case ShutdownMode.OnLastWindowClose: |
|
||||
if (Count == 0) |
|
||||
{ |
|
||||
_application.Shutdown(); |
|
||||
} |
|
||||
|
|
||||
break; |
|
||||
case ShutdownMode.OnMainWindowClose: |
|
||||
if (window == _application.MainWindow) |
|
||||
{ |
|
||||
_application.Shutdown(); |
|
||||
} |
|
||||
|
|
||||
break; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -0,0 +1,213 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using Avalonia.Controls.ApplicationLifetimes; |
||||
|
using Avalonia.Platform; |
||||
|
using Avalonia.Threading; |
||||
|
using Avalonia.UnitTests; |
||||
|
using Moq; |
||||
|
using Xunit; |
||||
|
|
||||
|
namespace Avalonia.Controls.UnitTests |
||||
|
{ |
||||
|
|
||||
|
public class DesktopStyleApplicationLifetimeTests |
||||
|
{ |
||||
|
[Fact] |
||||
|
public void Should_Set_ExitCode_After_Shutdown() |
||||
|
{ |
||||
|
using (UnitTestApplication.Start(TestServices.MockThreadingInterface)) |
||||
|
using(var lifetime = new ClassicDesktopStyleApplicationLifetime(Application.Current)) |
||||
|
{ |
||||
|
lifetime.Shutdown(1337); |
||||
|
|
||||
|
var exitCode = lifetime.Start(Array.Empty<string>()); |
||||
|
|
||||
|
Assert.Equal(1337, exitCode); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
|
||||
|
[Fact] |
||||
|
public void Should_Close_All_Remaining_Open_Windows_After_Explicit_Exit_Call() |
||||
|
{ |
||||
|
using (UnitTestApplication.Start(TestServices.StyledWindow)) |
||||
|
using(var lifetime = new ClassicDesktopStyleApplicationLifetime(Application.Current)) |
||||
|
{ |
||||
|
var windows = new List<Window> { new Window(), new Window(), new Window(), new Window() }; |
||||
|
|
||||
|
foreach (var window in windows) |
||||
|
{ |
||||
|
window.Show(); |
||||
|
} |
||||
|
Assert.Equal(4, lifetime.Windows.Count); |
||||
|
lifetime.Shutdown(); |
||||
|
|
||||
|
Assert.Empty(lifetime.Windows); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Should_Only_Exit_On_Explicit_Exit() |
||||
|
{ |
||||
|
using (UnitTestApplication.Start(TestServices.StyledWindow)) |
||||
|
using(var lifetime = new ClassicDesktopStyleApplicationLifetime(Application.Current)) |
||||
|
{ |
||||
|
lifetime.ShutdownMode = ShutdownMode.OnExplicitShutdown; |
||||
|
|
||||
|
var hasExit = false; |
||||
|
|
||||
|
lifetime.Exit += (s, e) => hasExit = true; |
||||
|
|
||||
|
var windowA = new Window(); |
||||
|
|
||||
|
windowA.Show(); |
||||
|
|
||||
|
var windowB = new Window(); |
||||
|
|
||||
|
windowB.Show(); |
||||
|
|
||||
|
windowA.Close(); |
||||
|
|
||||
|
Assert.False(hasExit); |
||||
|
|
||||
|
windowB.Close(); |
||||
|
|
||||
|
Assert.False(hasExit); |
||||
|
|
||||
|
lifetime.Shutdown(); |
||||
|
|
||||
|
Assert.True(hasExit); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Should_Exit_After_MainWindow_Closed() |
||||
|
{ |
||||
|
using (UnitTestApplication.Start(TestServices.StyledWindow)) |
||||
|
using(var lifetime = new ClassicDesktopStyleApplicationLifetime(Application.Current)) |
||||
|
{ |
||||
|
lifetime.ShutdownMode = ShutdownMode.OnMainWindowClose; |
||||
|
|
||||
|
var hasExit = false; |
||||
|
|
||||
|
lifetime.Exit += (s, e) => hasExit = true; |
||||
|
|
||||
|
var mainWindow = new Window(); |
||||
|
|
||||
|
mainWindow.Show(); |
||||
|
|
||||
|
lifetime.MainWindow = mainWindow; |
||||
|
|
||||
|
var window = new Window(); |
||||
|
|
||||
|
window.Show(); |
||||
|
|
||||
|
mainWindow.Close(); |
||||
|
|
||||
|
Assert.True(hasExit); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Should_Exit_After_Last_Window_Closed() |
||||
|
{ |
||||
|
using (UnitTestApplication.Start(TestServices.StyledWindow)) |
||||
|
using(var lifetime = new ClassicDesktopStyleApplicationLifetime(Application.Current)) |
||||
|
{ |
||||
|
lifetime.ShutdownMode = ShutdownMode.OnLastWindowClose; |
||||
|
|
||||
|
var hasExit = false; |
||||
|
|
||||
|
lifetime.Exit += (s, e) => hasExit = true; |
||||
|
|
||||
|
var windowA = new Window(); |
||||
|
|
||||
|
windowA.Show(); |
||||
|
|
||||
|
var windowB = new Window(); |
||||
|
|
||||
|
windowB.Show(); |
||||
|
|
||||
|
windowA.Close(); |
||||
|
|
||||
|
Assert.False(hasExit); |
||||
|
|
||||
|
windowB.Close(); |
||||
|
|
||||
|
Assert.True(hasExit); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Show_Should_Add_Window_To_OpenWindows() |
||||
|
{ |
||||
|
using (UnitTestApplication.Start(TestServices.StyledWindow)) |
||||
|
using(var lifetime = new ClassicDesktopStyleApplicationLifetime(Application.Current)) |
||||
|
{ |
||||
|
var window = new Window(); |
||||
|
|
||||
|
window.Show(); |
||||
|
|
||||
|
Assert.Equal(new[] { window }, lifetime.Windows); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Window_Should_Be_Added_To_OpenWindows_Only_Once() |
||||
|
{ |
||||
|
using (UnitTestApplication.Start(TestServices.StyledWindow)) |
||||
|
using(var lifetime = new ClassicDesktopStyleApplicationLifetime(Application.Current)) |
||||
|
{ |
||||
|
var window = new Window(); |
||||
|
|
||||
|
window.Show(); |
||||
|
window.Show(); |
||||
|
window.IsVisible = true; |
||||
|
|
||||
|
Assert.Equal(new[] { window }, lifetime.Windows); |
||||
|
|
||||
|
window.Close(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Close_Should_Remove_Window_From_OpenWindows() |
||||
|
{ |
||||
|
using (UnitTestApplication.Start(TestServices.StyledWindow)) |
||||
|
using(var lifetime = new ClassicDesktopStyleApplicationLifetime(Application.Current)) |
||||
|
{ |
||||
|
var window = new Window(); |
||||
|
|
||||
|
window.Show(); |
||||
|
Assert.Equal(1, lifetime.Windows.Count); |
||||
|
window.Close(); |
||||
|
|
||||
|
Assert.Empty(lifetime.Windows); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Impl_Closing_Should_Remove_Window_From_OpenWindows() |
||||
|
{ |
||||
|
var windowImpl = new Mock<IWindowImpl>(); |
||||
|
windowImpl.SetupProperty(x => x.Closed); |
||||
|
windowImpl.Setup(x => x.Scaling).Returns(1); |
||||
|
|
||||
|
var services = TestServices.StyledWindow.With( |
||||
|
windowingPlatform: new MockWindowingPlatform(() => windowImpl.Object)); |
||||
|
|
||||
|
using (UnitTestApplication.Start(services)) |
||||
|
using(var lifetime = new ClassicDesktopStyleApplicationLifetime(Application.Current)) |
||||
|
{ |
||||
|
var window = new Window(); |
||||
|
|
||||
|
window.Show(); |
||||
|
Assert.Equal(1, lifetime.Windows.Count); |
||||
|
windowImpl.Object.Closed(); |
||||
|
|
||||
|
Assert.Empty(lifetime.Windows); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
} |
||||
Loading…
Reference in new issue