/************************************************************************************* Extended WPF Toolkit Copyright (C) 2007-2013 Xceed Software Inc. This program is provided to you under the terms of the Microsoft Public License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license For more features, controls, and fast professional support, pick up the Plus Edition at http://xceed.com/wpf_toolkit Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids ***********************************************************************************/ using System; using System.Windows; using System.Windows.Media; using System.Windows.Controls.Primitives; namespace Xceed.Wpf.Toolkit.Core.Utilities { internal static class TreeHelper { /// /// Tries its best to return the specified element's parent. It will /// try to find, in this order, the VisualParent, LogicalParent, LogicalTemplatedParent. /// It only works for Visual, FrameworkElement or FrameworkContentElement. /// /// The element to which to return the parent. It will only /// work if element is a Visual, a FrameworkElement or a FrameworkContentElement. /// If the logical parent is not found (Parent), we check the TemplatedParent /// (see FrameworkElement.Parent documentation). But, we never actually witnessed /// this situation. public static DependencyObject GetParent( DependencyObject element ) { return TreeHelper.GetParent( element, true ); } private static DependencyObject GetParent( DependencyObject element, bool recurseIntoPopup ) { if( recurseIntoPopup ) { // Case 126732 : To correctly detect parent of a popup we must do that exception case Popup popup = element as Popup; if( ( popup != null ) && ( popup.PlacementTarget != null ) ) return popup.PlacementTarget; } Visual visual = element as Visual; DependencyObject parent = ( visual == null ) ? null : VisualTreeHelper.GetParent( visual ); if( parent == null ) { // No Visual parent. Check in the logical tree. FrameworkElement fe = element as FrameworkElement; if( fe != null ) { parent = fe.Parent; if( parent == null ) { parent = fe.TemplatedParent; } } else { FrameworkContentElement fce = element as FrameworkContentElement; if( fce != null ) { parent = fce.Parent; if( parent == null ) { parent = fce.TemplatedParent; } } } } return parent; } /// /// This will search for a parent of the specified type. /// /// The type of the element to find /// The node where the search begins. This element is not checked. /// Returns the found element. Null if nothing is found. public static T FindParent( DependencyObject startingObject ) where T : DependencyObject { return TreeHelper.FindParent( startingObject, false, null ); } /// /// This will search for a parent of the specified type. /// /// The type of the element to find /// The node where the search begins. /// Should the specified startingObject be checked first. /// Returns the found element. Null if nothing is found. public static T FindParent( DependencyObject startingObject, bool checkStartingObject ) where T : DependencyObject { return TreeHelper.FindParent( startingObject, checkStartingObject, null ); } /// /// This will search for a parent of the specified type. /// /// The type of the element to find /// The node where the search begins. /// Should the specified startingObject be checked first. /// Provide a callback to check additional properties /// of the found elements. Can be left Null if no additional criteria are needed. /// Returns the found element. Null if nothing is found. /// Button button = TreeHelper.FindParent<Button>( this, foundChild => foundChild.Focusable ); public static T FindParent( DependencyObject startingObject, bool checkStartingObject, Func additionalCheck ) where T : DependencyObject { T foundElement; DependencyObject parent = ( checkStartingObject ? startingObject : TreeHelper.GetParent( startingObject, true ) ); while( parent != null ) { foundElement = parent as T; if( foundElement != null ) { if( additionalCheck == null ) { return foundElement; } else { if( additionalCheck( foundElement ) ) return foundElement; } } parent = TreeHelper.GetParent( parent, true ); } return null; } /// /// This will search for a child of the specified type. The search is performed /// hierarchically, breadth first (as opposed to depth first). /// /// The type of the element to find /// The root of the tree to search for. This element itself is not checked. /// Returns the found element. Null if nothing is found. public static T FindChild( DependencyObject parent ) where T : DependencyObject { return TreeHelper.FindChild( parent, null ); } /// /// This will search for a child of the specified type. The search is performed /// hierarchically, breadth first (as opposed to depth first). /// /// The type of the element to find /// The root of the tree to search for. This element itself is not checked. /// Provide a callback to check additional properties /// of the found elements. Can be left Null if no additional criteria are needed. /// Returns the found element. Null if nothing is found. /// Button button = TreeHelper.FindChild<Button>( this, foundChild => foundChild.Focusable ); public static T FindChild( DependencyObject parent, Func additionalCheck ) where T : DependencyObject { int childrenCount = VisualTreeHelper.GetChildrenCount( parent ); T child; for( int index = 0; index < childrenCount; index++ ) { child = VisualTreeHelper.GetChild( parent, index ) as T; if( child != null ) { if( additionalCheck == null ) { return child; } else { if( additionalCheck( child ) ) return child; } } } for( int index = 0; index < childrenCount; index++ ) { child = TreeHelper.FindChild( VisualTreeHelper.GetChild( parent, index ), additionalCheck ); if( child != null ) return child; } return null; } /// /// Returns true if the specified element is a child of parent somewhere in the visual /// tree. This method will work for Visual, FrameworkElement and FrameworkContentElement. /// /// The element that is potentially a child of the specified parent. /// The element that is potentially a parent of the specified element. public static bool IsDescendantOf( DependencyObject element, DependencyObject parent ) { return TreeHelper.IsDescendantOf( element, parent, true ); } /// /// Returns true if the specified element is a child of parent somewhere in the visual /// tree. This method will work for Visual, FrameworkElement and FrameworkContentElement. /// /// The element that is potentially a child of the specified parent. /// The element that is potentially a parent of the specified element. public static bool IsDescendantOf( DependencyObject element, DependencyObject parent, bool recurseIntoPopup ) { while( element != null ) { if( element == parent ) return true; element = TreeHelper.GetParent( element, recurseIntoPopup ); } return false; } } }