diff --git a/Perspex.Controls/Menu.cs b/Perspex.Controls/Menu.cs
index 924e8b4cec..982b550d89 100644
--- a/Perspex.Controls/Menu.cs
+++ b/Perspex.Controls/Menu.cs
@@ -132,16 +132,6 @@ namespace Perspex.Controls
this.subscription.Dispose();
}
- ///
- /// Called when the loses focus.
- ///
- /// The event args.
- protected override void OnLostFocus(RoutedEventArgs e)
- {
- base.OnLostFocus(e);
- //this.Close();
- }
-
///
/// Called when a key is pressed within the menu.
///
@@ -205,6 +195,8 @@ namespace Perspex.Controls
private void OnMenuClick(RoutedEventArgs e)
{
this.Close();
+ FocusManager.Instance.Focus(null);
+ e.Handled = true;
}
///
diff --git a/Perspex.Controls/PopupRoot.cs b/Perspex.Controls/PopupRoot.cs
index aaf7cbe948..01f1d318fb 100644
--- a/Perspex.Controls/PopupRoot.cs
+++ b/Perspex.Controls/PopupRoot.cs
@@ -11,11 +11,12 @@ namespace Perspex.Controls
using Perspex.Media;
using Perspex.Platform;
using Splat;
+ using Perspex.VisualTree;
///
/// The root window of a .
///
- public class PopupRoot : TopLevel, IInteractive
+ public class PopupRoot : TopLevel, IInteractive, IHostedVisualTreeRoot
{
///
/// Initializes static members of the class.
@@ -64,6 +65,14 @@ namespace Perspex.Controls
get { return this.Parent; }
}
+ ///
+ /// Gets the control that is hosting the popup root.
+ ///
+ IVisual IHostedVisualTreeRoot.Host
+ {
+ get { return this.Parent; }
+ }
+
///
/// Sets the position of the popup in screen coordinates.
///
diff --git a/Perspex.Input/FocusManager.cs b/Perspex.Input/FocusManager.cs
index 9f2a6db517..8d47ec6bf9 100644
--- a/Perspex.Input/FocusManager.cs
+++ b/Perspex.Input/FocusManager.cs
@@ -59,19 +59,29 @@ namespace Perspex.Input
{
if (control != null)
{
- var scope = control.GetSelfAndVisualAncestors()
- .OfType()
- .FirstOrDefault() ?? this.Scope;
+ var scope = GetFocusScopeAncestors(control)
+ .FirstOrDefault();
if (scope != null)
{
this.Scope = scope;
this.SetFocusedElement(scope, control, keyboardNavigated);
+ System.Diagnostics.Debug.WriteLine("Focused " + control.GetType().Name);
}
}
- else
+ else if (this.Current != null)
{
- this.SetFocusedElement(this.Scope, null);
+ // If control is null, set focus to the topmost focus scope.
+ foreach (var scope in GetFocusScopeAncestors(this.Current).Reverse().ToList())
+ {
+ IInputElement element;
+
+ if (this.focusScopes.TryGetValue(scope, out element))
+ {
+ this.Focus(element, keyboardNavigated);
+ break;
+ }
+ }
}
}
@@ -124,5 +134,26 @@ namespace Perspex.Input
this.Scope = scope;
this.Focus(e);
}
+
+ ///
+ /// Gets the focus scope ancestors of the specified control, traversing popups.
+ ///
+ /// The control.
+ /// The focus scopes.
+ private static IEnumerable GetFocusScopeAncestors(IInputElement control)
+ {
+ while (control != null)
+ {
+ var scope = control as IFocusScope;
+
+ if (scope != null)
+ {
+ yield return scope;
+ }
+
+ control = control.GetVisualParent() ??
+ ((control as IHostedVisualTreeRoot)?.Host as IInputElement);
+ }
+ }
}
}
diff --git a/Perspex.Input/MouseDevice.cs b/Perspex.Input/MouseDevice.cs
index e1102598a3..63f2dffae3 100644
--- a/Perspex.Input/MouseDevice.cs
+++ b/Perspex.Input/MouseDevice.cs
@@ -143,7 +143,7 @@ namespace Perspex.Input
IInputElement focusable = this.GetFocusable(hit);
- if (focusable != null && focusable.Focusable)
+ if (focusable != null && focusable.Focusable && focusable.IsEffectivelyVisible)
{
focusable.Focus();
}
diff --git a/Perspex.SceneGraph/Perspex.SceneGraph.csproj b/Perspex.SceneGraph/Perspex.SceneGraph.csproj
index 064cbc5a20..2026a0eabd 100644
--- a/Perspex.SceneGraph/Perspex.SceneGraph.csproj
+++ b/Perspex.SceneGraph/Perspex.SceneGraph.csproj
@@ -101,6 +101,7 @@
+
diff --git a/Perspex.SceneGraph/VisualTree/IHostedVisualTreeRoot.cs b/Perspex.SceneGraph/VisualTree/IHostedVisualTreeRoot.cs
new file mode 100644
index 0000000000..e76ae5ebde
--- /dev/null
+++ b/Perspex.SceneGraph/VisualTree/IHostedVisualTreeRoot.cs
@@ -0,0 +1,22 @@
+// -----------------------------------------------------------------------
+//
+// Copyright 2015 MIT Licence. See licence.md for more information.
+//
+// -----------------------------------------------------------------------
+
+namespace Perspex.VisualTree
+{
+ ///
+ /// Interface for controls that are at the root of a hosted visual tree, such as popups.
+ ///
+ public interface IHostedVisualTreeRoot
+ {
+ ///
+ /// Gets the visual tree host.
+ ///
+ ///
+ /// The visual tree host.
+ ///
+ IVisual Host { get; }
+ }
+}