Browse Source

Merge branch 'application.exit' of https://github.com/jkoritzinsky/Perspex into jkoritzinsky-application.exit

pull/464/head
Steven Kirk 11 years ago
parent
commit
92a03adfc5
  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. // 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. // Licensed under the MIT license. See licence.md file in the project root for full license information.
using Perspex;
using Perspex.Controls; using Perspex.Controls;
using Perspex.Diagnostics; using Perspex.Diagnostics;
using Perspex.Markup.Xaml; using Perspex.Markup.Xaml;
@ -10,6 +11,8 @@ namespace XamlTestApplication.Views
{ {
public class MainWindow : Window public class MainWindow : Window
{ {
private MenuItem _exitMenu;
public MainWindow() public MainWindow()
{ {
InitializeComponent(); InitializeComponent();
@ -20,6 +23,8 @@ namespace XamlTestApplication.Views
private void InitializeComponent() private void InitializeComponent()
{ {
PerspexXamlLoader.Load(this); 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"/> <Separator Background="Red"/>
<MenuItem Header="_Test"/> <MenuItem Header="_Test"/>
<Separator/> <Separator/>
<MenuItem Header="_World"/> <MenuItem Name="exitMenu" Header="_Exit"/>
</MenuItem> </MenuItem>
</Menu> </Menu>
<TabControl Grid.Row="1" Grid.ColumnSpan="2" Padding="5"> <TabControl Grid.Row="1" Grid.ColumnSpan="2" Padding="5">

31
src/Perspex.Application/Application.cs

@ -32,7 +32,7 @@ namespace Perspex
/// method. /// method.
/// - Tracks the lifetime of the application. /// - Tracks the lifetime of the application.
/// </remarks> /// </remarks>
public class Application : IGlobalDataTemplates, IGlobalStyles, IStyleRoot public class Application : IGlobalDataTemplates, IGlobalStyles, IStyleRoot, IApplicationLifecycle
{ {
static Action _platformInitializationCallback; static Action _platformInitializationCallback;
@ -56,6 +56,7 @@ namespace Perspex
} }
PerspexLocator.CurrentMutable.BindToSelf(this); PerspexLocator.CurrentMutable.BindToSelf(this);
OnExit += OnExiting;
} }
/// <summary> /// <summary>
@ -138,10 +139,35 @@ namespace Perspex
public void Run(ICloseable closable) public void Run(ICloseable closable)
{ {
var source = new CancellationTokenSource(); var source = new CancellationTokenSource();
closable.Closed += OnExiting;
closable.Closed += (s, e) => source.Cancel(); closable.Closed += (s, e) => source.Cancel();
Dispatcher.UIThread.MainLoop(source.Token); 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> /// <summary>
/// Register's the services needed by Perspex. /// Register's the services needed by Perspex.
/// </summary> /// </summary>
@ -160,7 +186,8 @@ namespace Perspex
.Bind<IKeyboardNavigationHandler>().ToTransient<KeyboardNavigationHandler>() .Bind<IKeyboardNavigationHandler>().ToTransient<KeyboardNavigationHandler>()
.Bind<IStyler>().ToConstant(_styler) .Bind<IStyler>().ToConstant(_styler)
.Bind<ILayoutManager>().ToSingleton<LayoutManager>() .Bind<ILayoutManager>().ToSingleton<LayoutManager>()
.Bind<IRenderQueueManager>().ToTransient<RenderQueueManager>(); .Bind<IRenderQueueManager>().ToTransient<RenderQueueManager>()
.Bind<IApplicationLifecycle>().ToConstant(this);
} }
/// <summary> /// <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\ItemContainer.cs" />
<Compile Include="Generators\TreeContainerIndex.cs" /> <Compile Include="Generators\TreeContainerIndex.cs" />
<Compile Include="HotkeyManager.cs" /> <Compile Include="HotkeyManager.cs" />
<Compile Include="IApplicationLifecycle.cs" />
<Compile Include="INameScope.cs" /> <Compile Include="INameScope.cs" />
<Compile Include="IPseudoClasses.cs" /> <Compile Include="IPseudoClasses.cs" />
<Compile Include="DropDownItem.cs" /> <Compile Include="DropDownItem.cs" />

20
src/Perspex.Controls/TopLevel.cs

@ -48,6 +48,7 @@ namespace Perspex.Controls
private readonly IInputManager _inputManager; private readonly IInputManager _inputManager;
private readonly IAccessKeyHandler _accessKeyHandler; private readonly IAccessKeyHandler _accessKeyHandler;
private readonly IKeyboardNavigationHandler _keyboardNavigationHandler; private readonly IKeyboardNavigationHandler _keyboardNavigationHandler;
private readonly IApplicationLifecycle _applicationLifecycle;
private Size _clientSize; private Size _clientSize;
private bool _isActive; private bool _isActive;
@ -92,6 +93,7 @@ namespace Perspex.Controls
_inputManager = TryGetService<IInputManager>(dependencyResolver); _inputManager = TryGetService<IInputManager>(dependencyResolver);
_keyboardNavigationHandler = TryGetService<IKeyboardNavigationHandler>(dependencyResolver); _keyboardNavigationHandler = TryGetService<IKeyboardNavigationHandler>(dependencyResolver);
_renderQueueManager = TryGetService<IRenderQueueManager>(dependencyResolver); _renderQueueManager = TryGetService<IRenderQueueManager>(dependencyResolver);
_applicationLifecycle = TryGetService<IApplicationLifecycle>(dependencyResolver);
(TryGetService<ITopLevelRenderer>(dependencyResolver) ?? new DefaultTopLevelRenderer()).Attach(this); (TryGetService<ITopLevelRenderer>(dependencyResolver) ?? new DefaultTopLevelRenderer()).Attach(this);
PlatformImpl.SetInputRoot(this); PlatformImpl.SetInputRoot(this);
@ -112,6 +114,11 @@ namespace Perspex.Controls
.Select( .Select(
x => (x as InputElement)?.GetObservable(CursorProperty) ?? Observable.Empty<Cursor>()) x => (x as InputElement)?.GetObservable(CursorProperty) ?? Observable.Empty<Cursor>())
.Switch().Subscribe(cursor => PlatformImpl.SetCursor(cursor?.PlatformCursor)); .Switch().Subscribe(cursor => PlatformImpl.SetCursor(cursor?.PlatformCursor));
if (_applicationLifecycle != null)
{
_applicationLifecycle.OnExit += OnApplicationExiting;
}
} }
/// <summary> /// <summary>
@ -347,6 +354,19 @@ namespace Perspex.Controls
private void HandleClosed() private void HandleClosed()
{ {
Closed?.Invoke(this, EventArgs.Empty); 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> /// <summary>

6
src/Perspex.Controls/Window.cs

@ -156,6 +156,12 @@ namespace Perspex.Controls
PlatformImpl.Dispose(); PlatformImpl.Dispose();
} }
protected override void HandleApplicationExiting()
{
base.HandleApplicationExiting();
Close();
}
/// <summary> /// <summary>
/// Closes a dialog window with the specified result. /// Closes a dialog window with the specified result.
/// </summary> /// </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() private FuncControlTemplate<TestTopLevel> CreateTemplate()
{ {
return new FuncControlTemplate<TestTopLevel>(x => return new FuncControlTemplate<TestTopLevel>(x =>
@ -284,10 +297,18 @@ namespace Perspex.Controls.UnitTests
private class TestTopLevel : TopLevel private class TestTopLevel : TopLevel
{ {
public bool IsClosed { get; private set; }
public TestTopLevel(ITopLevelImpl impl) public TestTopLevel(ITopLevelImpl impl)
: base(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.Layout;
using Perspex.Platform; using Perspex.Platform;
using Perspex.Styling; using Perspex.Styling;
using Perspex.Controls;
namespace Perspex.UnitTests namespace Perspex.UnitTests
{ {
@ -47,7 +48,8 @@ namespace Perspex.UnitTests
.Bind<IPlatformThreadingInterface>().ToConstant(Services.ThreadingInterface) .Bind<IPlatformThreadingInterface>().ToConstant(Services.ThreadingInterface)
.Bind<IStandardCursorFactory>().ToConstant(Services.StandardCursorFactory) .Bind<IStandardCursorFactory>().ToConstant(Services.StandardCursorFactory)
.Bind<IStyler>().ToConstant(Services.Styler) .Bind<IStyler>().ToConstant(Services.Styler)
.Bind<IWindowingPlatform>().ToConstant(Services.WindowingPlatform); .Bind<IWindowingPlatform>().ToConstant(Services.WindowingPlatform)
.Bind<IApplicationLifecycle>().ToConstant(this);
} }
} }
} }

Loading…
Cancel
Save