Finding last visual parent in VisualTree

Recently I had a requirement where I needed to find the last parent of a particular type in VisualTree. You can easily find an implementation to find the parent but was not able to find one for finding the top most parent of a given type. So I modified the current implementation to get the last parent of a given type in the hierarchy, which was not tough at all. This method is useful when you can have multiple parents of same type in hierarchy and you need to find the top most parent of type T, e.g. having multiple nested ScrollViewer’s. I will post the exact requirement I had and how this method was used to implement that in a later post.

using System.Windows;
using System.Windows.Media;
 
namespace WpfExtensions
{
    public static class DependencyObjectExtension
    {
        /// <summary>
        /// Gets the last visual parent.
        /// </summary>
        /// <param name="obj">Element whose last parent is required.</param>
        /// <returns>The last parent obj. of type T</returns>
        /// <remarks>
        /// This method is useful when you can have multiple parents of same type in hierarchy 
        /// and you need to find the top most parent of type T
        /// e.g. having multiple nested ScrollViewer’s
        /// </remarks>
        public static T GetLastVisualAncestor<T>(this DependencyObject obj) where T : DependencyObject
        {
            if (obj != null)
            {
                T lastParentFound = null;
 
                // Keep traversing the tree upwards till Root
                while (obj != null)
                {
                    T objTest = obj as T;
                    if (objTest != null)
                    {
                        // A parent of desired type found
                        lastParentFound = objTest;
                    }
 
                    // Check for more parent objects of type T
                    obj = obj.GetAncestor<T>();
                }
 
                // Reached the top of Visual tree, return last found Parent of type T
                return lastParentFound;
            }
 
            return null;
        }        
 
        /// <summary>
        /// From http://www.hardcodet.net/2008/02/find-wpf-parent
        /// This method is an alternative to WPF's
        /// <see cref="VisualTreeHelper.GetParent"/> method, which also
        /// supports content elements. Keep in mind that for content element,
        /// this method falls back to the logical tree of the element!
        /// </summary>
        /// <param name="child">The item to be processed.</param>
        /// <returns>The submitted item's parent, if available. Otherwise
        /// null.</returns>
        private static DependencyObject GetParentObject(this DependencyObject child)
        {
            if (child == null)
            {
                return null;
            }
 
            // handle content elements separately
            ContentElement contentElement = child as ContentElement;
            if (contentElement != null)
            {
                DependencyObject parent = ContentOperations.GetParent(contentElement);
                if (parent != null)
                {
                    return parent;
                }
 
                FrameworkContentElement fce = contentElement as FrameworkContentElement;
                return fce != null ? fce.Parent : null;
            }
 
            // also try searching for parent in framework elements (such as DockPanel, etc.)
            FrameworkElement frameworkElement = child as FrameworkElement;
            if (frameworkElement != null && frameworkElement.Parent != null)
            {
                return frameworkElement.Parent;
            }
 
            // if it's not a ContentElement/FrameworkElement, rely on VisualTreeHelper
            return VisualTreeHelper.GetParent(child);
        }
 
        /// <summary>
        /// Finds a parent of a given item on the visual tree.
        /// </summary>
        /// <typeparam name="T">The type of the queried item.</typeparam>
        /// <param name="child">A direct or indirect child of the queried item.</param>
        /// <returns>The first parent item that matches the submitted type parameter. 
        /// If no matching item can be found, a null reference is returned.</returns>
        public static T GetAncestor<T>(this DependencyObject child) where T : DependencyObject
        {
            DependencyObject current = child;
 
            while (current != null)
            {
                current = GetParentObject(current);
 
                T result = current as T;
                if (result != null)
                {
                    return result;
                }
            }
 
            return null;
        }
    }
}

No Comments

Add a Comment

As it will appear on the website

Not displayed

Your website