All the controls missing in WPF. Over 1 million downloads.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

238 lines
9.3 KiB

/************************************************************************
Extended WPF Toolkit
Copyright (C) 2010-2012 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
This program can be provided to you by Xceed Software Inc. under a
proprietary commercial license agreement for use in non-Open Source
projects. The commercial version of Extended WPF Toolkit also includes
priority technical support, commercial updates, and many additional
useful WPF controls if you license Xceed Business Suite for WPF.
Visit http://xceed.com and follow @datagrid on Twitter.
**********************************************************************/
using System;
using System.Windows;
using System.Windows.Media;
using System.Windows.Controls.Primitives;
namespace Xceed.Wpf.Toolkit.Core.Utilities
{
internal static class TreeHelper
{
/// <summary>
/// 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.
/// </summary>
/// <param name="element">The element to which to return the parent. It will only
/// work if element is a Visual, a FrameworkElement or a FrameworkContentElement.</param>
/// <remarks>If the logical parent is not found (Parent), we check the TemplatedParent
/// (see FrameworkElement.Parent documentation). But, we never actually witnessed
/// this situation.</remarks>
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;
}
/// <summary>
/// This will search for a parent of the specified type.
/// </summary>
/// <typeparam name="T">The type of the element to find</typeparam>
/// <param name="startingObject">The node where the search begins. This element is not checked.</param>
/// <returns>Returns the found element. Null if nothing is found.</returns>
public static T FindParent<T>( DependencyObject startingObject ) where T : DependencyObject
{
return TreeHelper.FindParent<T>( startingObject, false, null );
}
/// <summary>
/// This will search for a parent of the specified type.
/// </summary>
/// <typeparam name="T">The type of the element to find</typeparam>
/// <param name="startingObject">The node where the search begins.</param>
/// <param name="checkStartingObject">Should the specified startingObject be checked first.</param>
/// <returns>Returns the found element. Null if nothing is found.</returns>
public static T FindParent<T>( DependencyObject startingObject, bool checkStartingObject ) where T : DependencyObject
{
return TreeHelper.FindParent<T>( startingObject, checkStartingObject, null );
}
/// <summary>
/// This will search for a parent of the specified type.
/// </summary>
/// <typeparam name="T">The type of the element to find</typeparam>
/// <param name="startingObject">The node where the search begins.</param>
/// <param name="checkStartingObject">Should the specified startingObject be checked first.</param>
/// <param name="additionalCheck">Provide a callback to check additional properties
/// of the found elements. Can be left Null if no additional criteria are needed.</param>
/// <returns>Returns the found element. Null if nothing is found.</returns>
/// <example>Button button = TreeHelper.FindParent&lt;Button&gt;( this, foundChild => foundChild.Focusable );</example>
public static T FindParent<T>( DependencyObject startingObject, bool checkStartingObject, Func<T, bool> 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;
}
/// <summary>
/// This will search for a child of the specified type. The search is performed
/// hierarchically, breadth first (as opposed to depth first).
/// </summary>
/// <typeparam name="T">The type of the element to find</typeparam>
/// <param name="parent">The root of the tree to search for. This element itself is not checked.</param>
/// <returns>Returns the found element. Null if nothing is found.</returns>
public static T FindChild<T>( DependencyObject parent ) where T : DependencyObject
{
return TreeHelper.FindChild<T>( parent, null );
}
/// <summary>
/// This will search for a child of the specified type. The search is performed
/// hierarchically, breadth first (as opposed to depth first).
/// </summary>
/// <typeparam name="T">The type of the element to find</typeparam>
/// <param name="parent">The root of the tree to search for. This element itself is not checked.</param>
/// <param name="additionalCheck">Provide a callback to check additional properties
/// of the found elements. Can be left Null if no additional criteria are needed.</param>
/// <returns>Returns the found element. Null if nothing is found.</returns>
/// <example>Button button = TreeHelper.FindChild&lt;Button&gt;( this, foundChild => foundChild.Focusable );</example>
public static T FindChild<T>( DependencyObject parent, Func<T, bool> 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<T>( VisualTreeHelper.GetChild( parent, index ), additionalCheck );
if( child != null )
return child;
}
return null;
}
/// <summary>
/// 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.
/// </summary>
/// <param name="element">The element that is potentially a child of the specified parent.</param>
/// <param name="parent">The element that is potentially a parent of the specified element.</param>
public static bool IsDescendantOf( DependencyObject element, DependencyObject parent )
{
return TreeHelper.IsDescendantOf( element, parent, true );
}
/// <summary>
/// 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.
/// </summary>
/// <param name="element">The element that is potentially a child of the specified parent.</param>
/// <param name="parent">The element that is potentially a parent of the specified element.</param>
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;
}
}
}