// Helper method that performs a recursive, depth-first search of children starting at the specified parent, // looking for any children that conform to the specified Type and are marked with a SelectionStop // private static T FindChildSelectionStop <T>(DependencyObject parent, int leftIndex, int rightIndex, SearchDirection iterationDirection, int maxDepth, MatchDirection matchDirection) where T : DependencyObject { if (parent == null || maxDepth <= 0) { return(null); } int step = iterationDirection == SearchDirection.Next ? 1 : -1; int index = iterationDirection == SearchDirection.Next ? leftIndex : rightIndex; for (; index >= leftIndex && index <= rightIndex; index = index + step) { DependencyObject child = VisualTreeHelper.GetChild(parent, index); // If MatchDirection is set to Down, do an eligibility match BEFORE we dive down into // more children. // if (matchDirection == MatchDirection.Down && IsEligibleSelectionStop <T>(child)) { return((T)child); } // If this child is not an eligible SelectionStop because it is not visible, // there is no point digging down to get to more children. // if (!VisualTreeUtils.IsVisible(child as UIElement)) { continue; } int grandChildrenCount = VisualTreeHelper.GetChildrenCount(child); if (grandChildrenCount > 0 && IsExpanded(child)) { T element = FindChildSelectionStop <T>(child, 0, grandChildrenCount - 1, iterationDirection, maxDepth - 1, matchDirection); if (element != null) { return(element); } } // If MatchDirection is set to Up, do an eligibility match AFTER we tried diving into // more children and failed to find something we could return. // if (matchDirection == MatchDirection.Up && IsEligibleSelectionStop <T>(child)) { return((T)child); } } return(null); }
// Helper method used from GetNeighborSelectionStop() // Returns a parent DependencyObject of the specified element that is // // * Visible AND // * ( Marked with a SelectionStop OR // * Marked with IsSelectionScope = true OR // * Has more than one child ) // private static DependencyObject GetEligibleParent(DependencyObject element, out int childIndex, out int childrenCount, out int childDepth, out bool isSelectionStop, out bool isSelectionScope) { childDepth = 0; isSelectionStop = false; isSelectionScope = false; bool isVisible; do { element = VisualTreeUtils.GetIndexedVisualParent(element, out childrenCount, out childIndex); isSelectionStop = element == null ? false : (GetSelectionStop(element) != null); isSelectionScope = element == null ? false : GetIsSelectionScope(element); isVisible = VisualTreeUtils.IsVisible(element as UIElement); childDepth++; }while ( element != null && (isVisible == false || (isSelectionStop == false && isSelectionScope == false && childrenCount < 2))); return(element); }
// Helper method that return true if the given element is marked with a SelectionStop, // if it derives from the specified Type, and if it is Visible (assuming it derives from UIElement) // private static bool IsEligibleSelectionStop <T>(DependencyObject element) where T : DependencyObject { return((GetSelectionStop(element) != null) && typeof(T).IsAssignableFrom(element.GetType()) && VisualTreeUtils.IsVisible(element as UIElement)); }