private static void OnIsModalChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { ModalContentPresenter control = (ModalContentPresenter)d; if ((bool)e.NewValue == true) { /* * Cache the keyboard navigation mode of the primary content before setting it to * 'none' so that it can be restored when the modal content is hidden. */ control.cachedTabNavigationMode = KeyboardNavigation.GetTabNavigation(control.primaryContentPresenter); control.cachedDirectionalNavigationMode = KeyboardNavigation.GetDirectionalNavigation(control.primaryContentPresenter); control.cachedFocusedElement = Keyboard.FocusedElement; KeyboardNavigation.SetTabNavigation(control.primaryContentPresenter, KeyboardNavigationMode.None); KeyboardNavigation.SetDirectionalNavigation(control.primaryContentPresenter, KeyboardNavigationMode.None); /* * Show the overlay (which in turn shows the modal content as it is a child of * the overlay) and move focus to the first logical element. */ control.overlay.Visibility = Visibility.Visible; control.overlay.MoveFocus(traversalDirection); control.RaiseModalContentShownEvents(); } else { /* * Hide the overlay (which also hides the modal content...). */ control.overlay.Visibility = Visibility.Hidden; /* * Restore the cached keyboard navigation value on the primary content and move * focus to its first logical element. */ KeyboardNavigation.SetTabNavigation(control.primaryContentPresenter, control.cachedTabNavigationMode); KeyboardNavigation.SetDirectionalNavigation(control.primaryContentPresenter, control.cachedDirectionalNavigationMode); Keyboard.Focus(control.cachedFocusedElement); control.primaryContentPresenter.MoveFocus(traversalDirection); control.RaiseModalContentHiddenEvents(); } }
/// <summary> /// Gets the focusable descendents of the specified element. /// </summary> /// <param name="element">The element.</param> /// <returns>The element's focusable descendents.</returns> private static IEnumerable <IInputElement> GetFocusableDescendents(IInputElement element) { var mode = KeyboardNavigation.GetDirectionalNavigation((InputElement)element); var children = element.GetVisualChildren().OfType <IInputElement>(); foreach (var child in children) { if (child.CanFocus()) { yield return(child); } if (child.CanFocusDescendents()) { foreach (var descendent in GetFocusableDescendents(child)) { yield return(descendent); } } } }
/// <summary> /// Gets the next control in the specified navigation direction. /// </summary> /// <param name="element">The element.</param> /// <param name="direction">The navigation direction.</param> /// <returns> /// The next element in the specified direction, or null if <paramref name="element"/> /// was the last in the requested direction. /// </returns> public static IInputElement GetNext( IInputElement element, FocusNavigationDirection direction) { Contract.Requires <ArgumentNullException>(element != null); Contract.Requires <ArgumentException>( direction != FocusNavigationDirection.Next && direction != FocusNavigationDirection.Previous); var container = element.GetVisualParent <IInputElement>(); if (container != null) { var isForward = IsForward(direction); var mode = KeyboardNavigation.GetDirectionalNavigation((InputElement)container); switch (mode) { case KeyboardNavigationMode.Continue: return(GetNextInContainer(element, container, direction) ?? GetFirstInNextContainer(element, direction)); case KeyboardNavigationMode.Cycle: return(GetNextInContainer(element, container, direction) ?? GetFocusableDescendent(container, direction)); case KeyboardNavigationMode.Contained: return(GetNextInContainer(element, container, direction)); default: return(null); } } else { return(GetFocusableDescendents(element).FirstOrDefault()); } }