Browse Source

Merge branch 'jkoritzinsky-application.exit'

pull/464/head
Steven Kirk 10 years ago
parent
commit
7e9756993f
  1. 5
      samples/XamlTestApplicationPcl/Views/MainWindow.cs
  2. 2
      samples/XamlTestApplicationPcl/Views/MainWindow.paml
  3. 31
      src/Perspex.Application/Application.cs
  4. 24
      src/Perspex.Controls/IApplicationLifecycle.cs
  5. 1
      src/Perspex.Controls/Perspex.Controls.csproj
  6. 20
      src/Perspex.Controls/TopLevel.cs
  7. 6
      src/Perspex.Controls/Window.cs
  8. 21
      tests/Perspex.Controls.UnitTests/TopLevelTests.cs
  9. 4
      tests/Perspex.UnitTests/UnitTestApplication.cs

5
samples/XamlTestApplicationPcl/Views/MainWindow.cs

@ -1,6 +1,7 @@
// Copyright (c) The Perspex Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using Perspex;
using Perspex.Controls;
using Perspex.Diagnostics;
using Perspex.Markup.Xaml;
@ -10,6 +11,8 @@ namespace XamlTestApplication.Views
{
public class MainWindow : Window
{
private MenuItem _exitMenu;
public MainWindow()
{
InitializeComponent();
@ -20,6 +23,8 @@ namespace XamlTestApplication.Views
private void InitializeComponent()
{
PerspexXamlLoader.Load(this);
_exitMenu = this.FindControl<MenuItem>("exitMenu");
_exitMenu.Click += (s, e) => Application.Current.Exit();
}
}
}

2
samples/XamlTestApplicationPcl/Views/MainWindow.paml

@ -17,7 +17,7 @@
<Separator Background="Red"/>
<MenuItem Header="_Test"/>
<Separator/>
<MenuItem Header="_World"/>
<MenuItem Name="exitMenu" Header="_Exit"/>
</MenuItem>
</Menu>
<TabControl Grid.Row="1" Grid.ColumnSpan="2" Padding="5">

31
src/Perspex.Application/Application.cs

@ -32,7 +32,7 @@ namespace Perspex
/// method.
/// - Tracks the lifetime of the application.
/// </remarks>
public class Application : IGlobalDataTemplates, IGlobalStyles, IStyleRoot
public class Application : IGlobalDataTemplates, IGlobalStyles, IStyleRoot, IApplicationLifecycle
{
static Action _platformInitializationCallback;
@ -56,6 +56,7 @@ namespace Perspex
}
PerspexLocator.CurrentMutable.BindToSelf(this);
OnExit += OnExiting;
}
/// <summary>
@ -138,10 +139,35 @@ namespace Perspex
public void Run(ICloseable closable)
{
var source = new CancellationTokenSource();
closable.Closed += OnExiting;
closable.Closed += (s, e) => source.Cancel();
Dispatcher.UIThread.MainLoop(source.Token);
}
/// <summary>
/// Exits the application
/// </summary>
public void Exit()
{
OnExit?.Invoke(this, EventArgs.Empty);
}
/// <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 Perspex.
/// </summary>
@ -160,7 +186,8 @@ namespace Perspex
.Bind<IKeyboardNavigationHandler>().ToTransient<KeyboardNavigationHandler>()
.Bind<IStyler>().ToConstant(_styler)
.Bind<ILayoutManager>().ToSingleton<LayoutManager>()
.Bind<IRenderQueueManager>().ToTransient<RenderQueueManager>();
.Bind<IRenderQueueManager>().ToTransient<RenderQueueManager>()
.Bind<IApplicationLifecycle>().ToConstant(this);
}
/// <summary>

24
src/Perspex.Controls/IApplicationLifecycle.cs

@ -0,0 +1,24 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Perspex.Controls
{
/// <summary>
/// Sends events about the application lifecycle.
/// </summary>
public interface IApplicationLifecycle
{
/// <summary>
/// Sent when the application is exiting.
/// </summary>
event EventHandler OnExit;
/// <summary>
/// Exits the application.
/// </summary>
void Exit();
}
}

1
src/Perspex.Controls/Perspex.Controls.csproj

@ -50,6 +50,7 @@
<Compile Include="Generators\ItemContainer.cs" />
<Compile Include="Generators\TreeContainerIndex.cs" />
<Compile Include="HotkeyManager.cs" />
<Compile Include="IApplicationLifecycle.cs" />
<Compile Include="INameScope.cs" />
<Compile Include="IPseudoClasses.cs" />
<Compile Include="DropDownItem.cs" />

20
src/Perspex.Controls/TopLevel.cs

@ -48,6 +48,7 @@ namespace Perspex.Controls
private readonly IInputManager _inputManager;
private readonly IAccessKeyHandler _accessKeyHandler;
private readonly IKeyboardNavigationHandler _keyboardNavigationHandler;
private readonly IApplicationLifecycle _applicationLifecycle;
private Size _clientSize;
private bool _isActive;
@ -92,6 +93,7 @@ namespace Perspex.Controls
_inputManager = TryGetService<IInputManager>(dependencyResolver);
_keyboardNavigationHandler = TryGetService<IKeyboardNavigationHandler>(dependencyResolver);
_renderQueueManager = TryGetService<IRenderQueueManager>(dependencyResolver);
_applicationLifecycle = TryGetService<IApplicationLifecycle>(dependencyResolver);
(TryGetService<ITopLevelRenderer>(dependencyResolver) ?? new DefaultTopLevelRenderer()).Attach(this);
PlatformImpl.SetInputRoot(this);
@ -112,6 +114,11 @@ namespace Perspex.Controls
.Select(
x => (x as InputElement)?.GetObservable(CursorProperty) ?? Observable.Empty<Cursor>())
.Switch().Subscribe(cursor => PlatformImpl.SetCursor(cursor?.PlatformCursor));
if (_applicationLifecycle != null)
{
_applicationLifecycle.OnExit += OnApplicationExiting;
}
}
/// <summary>
@ -347,6 +354,19 @@ namespace Perspex.Controls
private void HandleClosed()
{
Closed?.Invoke(this, EventArgs.Empty);
_applicationLifecycle.OnExit -= OnApplicationExiting;
}
private void OnApplicationExiting(object sender, EventArgs args)
{
HandleApplicationExiting();
}
/// <summary>
/// Handles the application exiting, either from the last window closing, or a call to <see cref="IApplicationLifecycle.Exit"/>.
/// </summary>
protected virtual void HandleApplicationExiting()
{
}
/// <summary>

6
src/Perspex.Controls/Window.cs

@ -156,6 +156,12 @@ namespace Perspex.Controls
PlatformImpl.Dispose();
}
protected override void HandleApplicationExiting()
{
base.HandleApplicationExiting();
Close();
}
/// <summary>
/// Closes a dialog window with the specified result.
/// </summary>

21
tests/Perspex.Controls.UnitTests/TopLevelTests.cs

@ -272,6 +272,19 @@ namespace Perspex.Controls.UnitTests
}
}
[Fact]
public void Exiting_Application_Notifies_Top_Level()
{
using (UnitTestApplication.Start(TestServices.StyledWindow))
{
var impl = new Mock<ITopLevelImpl>();
impl.SetupAllProperties();
var target = new TestTopLevel(impl.Object);
UnitTestApplication.Current.Exit();
Assert.True(target.IsClosed);
}
}
private FuncControlTemplate<TestTopLevel> CreateTemplate()
{
return new FuncControlTemplate<TestTopLevel>(x =>
@ -284,10 +297,18 @@ namespace Perspex.Controls.UnitTests
private class TestTopLevel : TopLevel
{
public bool IsClosed { get; private set; }
public TestTopLevel(ITopLevelImpl impl)
: base(impl)
{
}
protected override void HandleApplicationExiting()
{
base.HandleApplicationExiting();
IsClosed = true;
}
}
}
}

4
tests/Perspex.UnitTests/UnitTestApplication.cs

@ -6,6 +6,7 @@ using Perspex.Input;
using Perspex.Layout;
using Perspex.Platform;
using Perspex.Styling;
using Perspex.Controls;
namespace Perspex.UnitTests
{
@ -47,7 +48,8 @@ namespace Perspex.UnitTests
.Bind<IPlatformThreadingInterface>().ToConstant(Services.ThreadingInterface)
.Bind<IStandardCursorFactory>().ToConstant(Services.StandardCursorFactory)
.Bind<IStyler>().ToConstant(Services.Styler)
.Bind<IWindowingPlatform>().ToConstant(Services.WindowingPlatform);
.Bind<IWindowingPlatform>().ToConstant(Services.WindowingPlatform)
.Bind<IApplicationLifecycle>().ToConstant(this);
}
}
}

Loading…
Cancel
Save