Browse Source

Correctly clear focus when control removed.

Focus was staying on removed element.
pull/519/head
Steven Kirk 11 years ago
parent
commit
ca301280e8
  1. 11
      src/Perspex.Input/FocusManager.cs
  2. 8
      src/Perspex.Input/InputElement.cs
  3. 49
      tests/Perspex.Input.UnitTests/InputElement_Focus.cs
  4. 5
      tests/Perspex.Input.UnitTests/Perspex.Input.UnitTests.csproj
  5. 3
      tests/Perspex.UnitTests/TestRoot.cs
  6. 15
      tests/Perspex.UnitTests/TestServices.cs
  7. 2
      tests/Perspex.UnitTests/UnitTestApplication.cs

11
src/Perspex.Input/FocusManager.cs

@ -39,7 +39,7 @@ namespace Perspex.Input
/// <summary>
/// Gets the currently focused <see cref="IInputElement"/>.
/// </summary>
public IInputElement Current => KeyboardDevice.Instance.FocusedElement;
public IInputElement Current => KeyboardDevice.Instance?.FocusedElement;
/// <summary>
/// Gets the current focus scope.
@ -82,9 +82,12 @@ namespace Perspex.Input
if (_focusScopes.TryGetValue(scope, out element))
{
Focus(element, method);
break;
return;
}
}
// Couldn't find a focus scope, clear focus.
SetFocusedElement(Scope, null);
}
}
@ -111,7 +114,7 @@ namespace Perspex.Input
if (Scope == scope)
{
KeyboardDevice.Instance.SetFocusedElement(element, method, modifiers);
KeyboardDevice.Instance?.SetFocusedElement(element, method, modifiers);
}
}
@ -176,7 +179,7 @@ namespace Perspex.Input
if (sender == e.Source)
{
var ev = (PointerPressedEventArgs)e;
var element = (ev.Device.Captured as IInputElement) ?? (e.Source as IInputElement);
var element = (ev.Device?.Captured as IInputElement) ?? (e.Source as IInputElement);
if (element == null || !CanFocus(element))
{

8
src/Perspex.Input/InputElement.cs

@ -376,9 +376,9 @@ namespace Perspex.Input
}
/// <inheritdoc/>
protected override void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e)
protected override void OnDetachedFromVisualTreeCore(VisualTreeAttachmentEventArgs e)
{
base.OnDetachedFromVisualTree(e);
base.OnDetachedFromVisualTreeCore(e);
if (IsFocused)
{
@ -387,9 +387,9 @@ namespace Perspex.Input
}
/// <inheritdoc/>
protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
protected override void OnAttachedToVisualTreeCore(VisualTreeAttachmentEventArgs e)
{
base.OnAttachedToVisualTree(e);
base.OnAttachedToVisualTreeCore(e);
UpdateIsEnabledCore();
}

49
tests/Perspex.Input.UnitTests/InputElement_Focus.cs

@ -0,0 +1,49 @@
// 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.Controls;
using Perspex.UnitTests;
using Xunit;
namespace Perspex.Input.UnitTests
{
public class InputElement_Focus
{
[Fact]
public void Focus_Should_Set_FocusManager_Current()
{
Button target;
using (UnitTestApplication.Start(TestServices.RealFocus))
{
var root = new TestRoot
{
Child = target = new Button()
};
target.Focus();
Assert.Same(target, FocusManager.Instance.Current);
}
}
[Fact]
public void Focus_Should_Be_Cleared_When_Control_Is_Removed_From_VisualTree()
{
Button target;
using (UnitTestApplication.Start(TestServices.RealFocus))
{
var root = new TestRoot
{
Child = target = new Button()
};
target.Focus();
root.Child = null;
Assert.Null(FocusManager.Instance.Current);
}
}
}
}

5
tests/Perspex.Input.UnitTests/Perspex.Input.UnitTests.csproj

@ -60,6 +60,7 @@
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="InputElement_Focus.cs" />
<Compile Include="InputElement_HitTesting.cs" />
<Compile Include="KeyboardNavigationTests_Arrows.cs" />
<Compile Include="KeyboardNavigationTests_Tab.cs" />
@ -103,6 +104,10 @@
<Project>{F1BAA01A-F176-4C6A-B39D-5B40BB1B148F}</Project>
<Name>Perspex.Styling</Name>
</ProjectReference>
<ProjectReference Include="..\Perspex.UnitTests\Perspex.UnitTests.csproj">
<Project>{88060192-33D5-4932-B0F9-8BD2763E857D}</Project>
<Name>Perspex.UnitTests</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />

3
tests/Perspex.UnitTests/TestRoot.cs

@ -3,6 +3,7 @@
using System;
using Perspex.Controls;
using Perspex.Input;
using Perspex.Layout;
using Perspex.Platform;
using Perspex.Rendering;
@ -10,7 +11,7 @@ using Perspex.Styling;
namespace Perspex.UnitTests
{
public class TestRoot : Decorator, ILayoutRoot, INameScope, IRenderRoot, IStyleRoot
public class TestRoot : Decorator, IFocusScope, ILayoutRoot, INameScope, IRenderRoot, IStyleRoot
{
private readonly NameScope _nameScope = new NameScope();

15
tests/Perspex.UnitTests/TestServices.cs

@ -36,12 +36,19 @@ namespace Perspex.UnitTests
public static readonly TestServices MockThreadingInterface = new TestServices(
threadingInterface: Mock.Of<IPlatformThreadingInterface>(x => x.CurrentThreadIsLoopThread == true));
public static readonly TestServices RealFocus = new TestServices(
focusManager: new FocusManager(),
keyboardDevice: () => new KeyboardDevice(),
inputManager: new InputManager());
public static readonly TestServices RealStyler = new TestServices(
styler: new Styler());
public TestServices(
IAssetLoader assetLoader = null,
IFocusManager focusManager = null,
IInputManager inputManager = null,
Func<IKeyboardDevice> keyboardDevice = null,
ILayoutManager layoutManager = null,
IPclPlatformWrapper platformWrapper = null,
IPlatformRenderInterface renderInterface = null,
@ -53,7 +60,9 @@ namespace Perspex.UnitTests
IWindowingPlatform windowingPlatform = null)
{
AssetLoader = assetLoader;
FocusManager = focusManager;
InputManager = inputManager;
KeyboardDevice = keyboardDevice;
LayoutManager = layoutManager;
PlatformWrapper = platformWrapper;
RenderInterface = renderInterface;
@ -67,6 +76,8 @@ namespace Perspex.UnitTests
public IAssetLoader AssetLoader { get; }
public IInputManager InputManager { get; }
public IFocusManager FocusManager { get; }
public Func<IKeyboardDevice> KeyboardDevice { get; }
public ILayoutManager LayoutManager { get; }
public IPclPlatformWrapper PlatformWrapper { get; }
public IPlatformRenderInterface RenderInterface { get; }
@ -79,7 +90,9 @@ namespace Perspex.UnitTests
public TestServices With(
IAssetLoader assetLoader = null,
IFocusManager focusManager = null,
IInputManager inputManager = null,
Func<IKeyboardDevice> keyboardDevice = null,
ILayoutManager layoutManager = null,
IPclPlatformWrapper platformWrapper = null,
IPlatformRenderInterface renderInterface = null,
@ -92,7 +105,9 @@ namespace Perspex.UnitTests
{
return new TestServices(
assetLoader: assetLoader ?? AssetLoader,
focusManager: focusManager ?? FocusManager,
inputManager: inputManager ?? InputManager,
keyboardDevice: keyboardDevice ?? KeyboardDevice,
layoutManager: layoutManager ?? LayoutManager,
platformWrapper: platformWrapper ?? PlatformWrapper,
renderInterface: renderInterface ?? RenderInterface,

2
tests/Perspex.UnitTests/UnitTestApplication.cs

@ -40,8 +40,10 @@ namespace Perspex.UnitTests
{
PerspexLocator.CurrentMutable
.Bind<IAssetLoader>().ToConstant(Services.AssetLoader)
.Bind<IFocusManager>().ToConstant(Services.FocusManager)
.BindToSelf<IGlobalStyles>(this)
.Bind<IInputManager>().ToConstant(Services.InputManager)
.Bind<IKeyboardDevice>().ToConstant(Services.KeyboardDevice?.Invoke())
.Bind<ILayoutManager>().ToConstant(Services.LayoutManager)
.Bind<IPclPlatformWrapper>().ToConstant(Services.PlatformWrapper)
.Bind<IPlatformRenderInterface>().ToConstant(Services.RenderInterface)

Loading…
Cancel
Save