// --------------------------------------------------------------------------------------------------------------------
// <copyright file="DependencyObjectExtensions.cs" company="Catel development team">
// Copyright (c) 2008 - 2011 Catel development team. All rights reserved.
// </copyright>
// <summary>
// Extension methods for the <see cref="DependencyObject" /> class.
// </summary>
// --------------------------------------------------------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
namespace Catel.Windows
{
/// <summary>
/// Extension methods for the <see cref="DependencyObject"/> class.
/// </summary>
public static class DependencyObjectExtensions
{
/// <summary>
/// Returns the ancestory object of a <see cref="DependencyObject"/>.
/// </summary>
/// <typeparam name="T">Ancestor object.</typeparam>
/// <param name="visualObject">Visual object to get the ancestor object for.</param>
/// <returns><see cref="DependencyObject"/> or null if no ancestor object is found.</returns>
/// <remarks>
/// If visualObject was of type T it was returned as ancestor, this is changed.
/// GetAncestorObject wil not return supplied parameter anymore.
/// </remarks>
public static T GetAncestorObject<T>(this DependencyObject visualObject)
{
object ancestorObject = null;
if (visualObject != null)
{
DependencyObject parentVisualObject = VisualTreeHelper.GetParent(visualObject);
if(parentVisualObject is T)
{
ancestorObject = parentVisualObject;
}
else
{
ancestorObject = GetAncestorObject<T>(parentVisualObject);
}
}
return (T)ancestorObject;
}
/// <summary>
/// Finds the logical or visual ancestor according to the predicate.
/// </summary>
/// <param name="startElement">The start element.</param>
/// <param name="condition">The condition.</param>
/// <returns>object or <c>null</c> if the ancestor is not found.</returns>
public static object FindLogicalOrVisualAncestor(this DependencyObject startElement, Predicate<object> condition)
{
return FindLogicalOrVisualAncestor(startElement, condition, -1);
}
/// <summary>
/// Finds the logical or visual ancestor according to the predicate.
/// </summary>
/// <param name="startElement">The start element.</param>
/// <param name="condition">The condition.</param>
/// <param name="maxDepth">The maximum number of levels to go up when searching for the parent. If smaller than 0, no maximum is used.</param>
/// <returns>object or <c>null</c> if the ancestor is not found.</returns>
public static object FindLogicalOrVisualAncestor(this DependencyObject startElement, Predicate<object> condition, int maxDepth)
{
#if !SILVERLIGHT
// Try to find logical ancestor one level up
object logicalAncestor = FindLogicalAncestor(startElement, condition, 1);
if (logicalAncestor != null)
{
return logicalAncestor;
}
#endif
// Try to find visual ancestor one level up
object visualAncestor = FindVisualAncestor(startElement, condition, 1);
if (visualAncestor != null)
{
return visualAncestor;
}
#if !SILVERLIGHT
// If we didn't find anything, try logical parent and call this method (recursive)
DependencyObject logicalParent = LogicalTreeHelper.GetParent(startElement);
if (logicalParent != null)
{
object lastResortLogicalAncestor = FindLogicalOrVisualAncestor(logicalParent, condition);
if (lastResortLogicalAncestor != null)
{
return lastResortLogicalAncestor;
}
}
#endif
// If we didn't find anything, try visual parent and call this method (recursive)
DependencyObject visualParent = VisualTreeHelper.GetParent(startElement);
if (visualParent != null)
{
object lastResortVisualAncestor = FindLogicalOrVisualAncestor(visualParent, condition);
if (lastResortVisualAncestor != null)
{
return lastResortVisualAncestor;
}
}
return null;
}
#if !SILVERLIGHT
/// <summary>
/// Finds the logical ancestor according to the predicate.
/// </summary>
/// <param name="startElement">The start element.</param>
/// <param name="condition">The condition.</param>
/// <returns>object or <c>null</c> if the ancestor is not found.</returns>
public static object FindLogicalAncestor(this DependencyObject startElement, Predicate<object> condition)
{
return FindLogicalAncestor(startElement, condition, -1);
}
/// <summary>
/// Finds the logical ancestor according to the predicate.
/// </summary>
/// <param name="startElement">The start element.</param>
/// <param name="condition">The condition.</param>
/// <param name="maxDepth">The maximum number of levels to go up when searching for the parent. If smaller than 0, no maximum is used.</param>
/// <returns>object or <c>null</c> if the ancestor is not found.</returns>
public static object FindLogicalAncestor(this DependencyObject startElement, Predicate<object> condition, int maxDepth)
{
DependencyObject obj = startElement;
while ((obj != null) && !condition(obj))
{
if (maxDepth == 0)
{
return null;
}
else if (maxDepth > 0)
{
maxDepth--;
}
obj = LogicalTreeHelper.GetParent(obj);
}
return obj;
}
/// <summary>
/// Finds the logical ancestor by type.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="startElement">The start element.</param>
/// <returns>object or <c>null</c> if the ancestor is not found.</returns>
public static T FindLogicalAncestorByType<T>(this DependencyObject startElement)
{
return (T)FindLogicalAncestor(startElement, delegate(object o) { return (o is T); });
}
/// <summary>
/// Finds the logical root.
/// </summary>
/// <param name="startElement">The start element.</param>
/// <returns>object or <c>null</c> if the ancestor is not found.</returns>
public static DependencyObject FindLogicalRoot(this DependencyObject startElement)
{
DependencyObject obj = null;
while (startElement != null)
{
obj = startElement;
startElement = LogicalTreeHelper.GetParent(startElement);
}
return obj;
}
#endif
/// <summary>
/// Finds the visual ancestor according to the predicate.
/// </summary>
/// <param name="startElement">The start element.</param>
/// <param name="condition">The condition.</param>
/// <returns>object or <c>null</c> if the ancestor is not found.</returns>
public static object FindVisualAncestor(this DependencyObject startElement, Predicate<object> condition)
{
return FindVisualAncestor(startElement, condition, -1);
}
/// <summary>
/// Finds the visual ancestor according to the predicate.
/// </summary>
/// <param name="startElement">The start element.</param>
/// <param name="condition">The condition.</param>
/// <param name="maxDepth">The maximum number of levels to go up when searching for the parent. If smaller than 0, no maximum is used.</param>
/// <returns>object or <c>null</c> if the ancestor is not found.</returns>
public static object FindVisualAncestor(this DependencyObject startElement, Predicate<object> condition, int maxDepth)
{
DependencyObject obj = startElement;
while ((obj != null) && !condition(obj))
{
if (maxDepth == 0)
{
return null;
}
else if (maxDepth > 0)
{
maxDepth--;
}
obj = VisualTreeHelper.GetParent(obj);
}
return obj;
}
/// <summary>
/// Finds the visual ancestor by type.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="startElement">The start element.</param>
/// <returns>object or <c>null</c> if the ancestor is not found.</returns>
public static T FindVisualAncestorByType<T>(this DependencyObject startElement)
{
return (T)FindVisualAncestor(startElement, delegate(object o) { return (o is T); });
}
/// <summary>
/// Finds the visual descendant.
/// </summary>
/// <param name="startElement">The start element.</param>
/// <param name="condition">The condition.</param>
/// <returns>object or <c>null</c> if the ancestor is not found.</returns>
public static DependencyObject FindVisualDescendant(this DependencyObject startElement, Predicate<object> condition)
{
if (startElement != null)
{
// Does the element match the condition?
if (condition(startElement))
{
return startElement;
}
// If the element is a content element, get the content
if (startElement is ContentControl)
{
// Only search content
return FindVisualDescendant(((ContentControl)startElement).Content as DependencyObject, condition);
}
// If the element has children, loop the children
if (startElement is Panel)
{
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(startElement); i++)
{
DependencyObject obj = FindVisualDescendant(VisualTreeHelper.GetChild(startElement, i), condition);
if (obj != null)
{
return obj;
}
}
}
}
return null;
}
/// <summary>
/// Finds the visual descendant by type.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="startElement">The start element.</param>
/// <returns>object or <c>null</c> if the ancestor is not found.</returns>
public static T FindVisualDescendantByType<T>(this DependencyObject startElement) where T : DependencyObject
{
return (T)FindVisualDescendant(startElement, delegate(object o) { return (o is T); });
}
/// <summary>
/// Finds the visual root.
/// </summary>
/// <param name="startElement">The start element.</param>
/// <returns>object or <c>null</c> if the ancestor is not found.</returns>
public static object FindVisualRoot(this DependencyObject startElement)
{
return FindVisualAncestor(startElement, delegate(object o)
{
DependencyObject dependencyObject = o as DependencyObject;
if (dependencyObject == null)
{
return false;
}
return (VisualTreeHelper.GetParent(o as DependencyObject) == null);
});
}
/// <summary>
/// Gets the visual children.
/// </summary>
/// <param name="parent">The parent.</param>
/// <returns>
/// <see cref="IEnumerable{DependencyObject}"/> of all children.
/// </returns>
public static IEnumerable<DependencyObject> GetVisualChildren(this DependencyObject parent)
{
int count = VisualTreeHelper.GetChildrenCount(parent);
for (int i = 0; i < count; ++i)
{
yield return VisualTreeHelper.GetChild(parent, i);
}
}
}
}