File: System\Windows\LogicalTreeHelper.cs
Web Access
Project: src\src\Microsoft.DotNet.Wpf\src\PresentationFramework\PresentationFramework.csproj (PresentationFramework)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
 
//
//
// Description: The LogicalTreeHelper class contains static methods that are
//  useful for performing common tasks with logical tree nodes.  There's nothing
//  here that the end user can't do themselves - but we do it for them and
//  gather them up here.
//
//
 
using System;
using System.Collections;   // In order to use IEnumerator
using System.Diagnostics;
using MS.Utility;           // In order to use SR
 
namespace System.Windows
{
/*
    public delegate bool ParentTraversalCallback(FrameworkElement parentFE, FrameworkContentElement parentFCE, object data);
    public delegate bool ChildTraversalCallback(FrameworkElement childFE, FrameworkContentElement childFCE, object child, object data);
*/
    
/// <summary>
/// Static helper functions for dealing with the logical tree
/// </summary>
public static class LogicalTreeHelper
{
    //------------------------------------------------------
    //
    //  Constructors
    //
    //------------------------------------------------------
 
    //------------------------------------------------------
    //
    //  Public Properties
    //
    //------------------------------------------------------
 
    // None
    
    //------------------------------------------------------
    //
    //  Public Methods
    //
    //------------------------------------------------------
 
    #region Public Methods
    
    /// <summary>
    /// Given an element in the logical tree to start searching from,
    /// searches all its descendent nodes in the logical tree a node whose Name 
    /// matches the specified elementName.
    /// The given DependencyObject must be either a FrameworkElement or FrameworkContentElement.
    /// </summary>
    /// <remarks>
    /// We're searching in a depth-first manner.  Review this if this turns out 
    ///  to be a performance problem.  We're doing this first because it's easy
    ///  and light on memory usage as compared to breadth-first.
    /// (RogerCh):It would be cool if the DFID (depth-first iterative-deepening)
    ///  algorithm would be useful here.
    /// </remarks>
    public static DependencyObject FindLogicalNode( DependencyObject logicalTreeNode, string elementName )
    {
        ArgumentNullException.ThrowIfNull(logicalTreeNode);
        ArgumentException.ThrowIfNullOrEmpty(elementName);
 
        DependencyObject namedElement = null;
        DependencyObject childNode = null;
 
        // Check given node against named element.
        IFrameworkInputElement selfNode = logicalTreeNode as IFrameworkInputElement;
        if( selfNode != null )
        {
            if( selfNode.Name == elementName )
            {
                namedElement = logicalTreeNode;
            }
        }
 
        if( namedElement == null )
        {
            // Nope, the given node isn't it.  See if we can check children.
            IEnumerator childEnumerator = null;
 
            childEnumerator = LogicalTreeHelper.GetLogicalChildren(logicalTreeNode);
 
            // If we can enumerate, check the children.
            if( childEnumerator != null )
            {
                childEnumerator.Reset();
                while( namedElement == null &&
                       childEnumerator.MoveNext() == true)
                {
                    childNode = childEnumerator.Current as DependencyObject;
 
                    if( childNode != null )
                    {
                        namedElement = FindLogicalNode( childNode, elementName );
                    }
                }
            }
        }
 
        // Return what we can find - may be null.
        return namedElement;
    }
 
    /// <summary>
    /// Get the logical parent of the given DependencyObject.
    /// The given DependencyObject must be either a FrameworkElement or FrameworkContentElement
    /// to have a logical parent.
    /// </summary>
    public static DependencyObject GetParent(DependencyObject current)
    {
        ArgumentNullException.ThrowIfNull(current);
 
        FrameworkElement fe = current as FrameworkElement;
        if (fe != null)
        {
            return fe.Parent;
        }
 
        FrameworkContentElement fce = current as FrameworkContentElement;
        if (fce != null)
        {
            return fce.Parent;
        }
 
        return null;
    }
 
    /// <summary>
    /// Get the logical children for the given DependencyObject.
    /// The given DependencyObject must be either a FrameworkElement or FrameworkContentElement
    /// to have logical children.
    /// </summary>
    public static IEnumerable GetChildren(DependencyObject current)
    {
        ArgumentNullException.ThrowIfNull(current);
 
        FrameworkElement fe = current as FrameworkElement;
        if (fe != null)
        {
            return new EnumeratorWrapper(fe.LogicalChildren);
        }
 
        FrameworkContentElement fce = current as FrameworkContentElement;
        if (fce != null)
        {
            return new EnumeratorWrapper(fce.LogicalChildren);
        }
 
        return EnumeratorWrapper.Empty;
    }
 
    /// <summary>
    /// Get the logical children for the given FrameworkElement
    /// </summary>
    public static IEnumerable GetChildren(FrameworkElement current)
    {
        ArgumentNullException.ThrowIfNull(current);
 
        return new EnumeratorWrapper(current.LogicalChildren);
    }
 
    /// <summary>
    /// Get the logical children for the given FrameworkContentElement
    /// </summary>
    public static IEnumerable GetChildren(FrameworkContentElement current)
    {
        ArgumentNullException.ThrowIfNull(current);
 
        return new EnumeratorWrapper(current.LogicalChildren);
    }
 
    /// <summary>
    /// Attempts to bring this element into view by originating a RequestBringIntoView event.
    /// </summary>
    public static void BringIntoView(DependencyObject current)
    {
        ArgumentNullException.ThrowIfNull(current);
 
        FrameworkElement fe = current as FrameworkElement;
        if (fe != null)
        {
            fe.BringIntoView();
        }
 
        FrameworkContentElement fce = current as FrameworkContentElement;
        if (fce != null)
        {
            fce.BringIntoView();
        }
    }
 
/*
    /// <summary>
    // fill this in
    /// </summary>
    public static bool WalkUpLogicalTree(DependencyObject startNode, ParentTraversalCallback callback, bool skipStart, in out object data)
    {
        FrameworkElement startFE = startNode as FrameworkElement;
        if (startFE != null)
        {
            return WalkUpLogicalTree(startFE, callback, skipStart, in out data);
        }
        else
        {
            FrameworkContentElement startFCE;
            if (startFCE != null)
            {
                return WalkUpLogicalTree(startFCE, callback, skipStart, in out data);
            }
            else
            {
                //  throw an exception
            }
        }
        return true;
    }
    
    /// <summary>
    //  fill this in
    /// </summary>
    public static bool WalkUpLogicalTree(FrameworkElement startNode, ParentTraversalCallback callback, bool skipStart, in out object data)
    {
        if (callback == null)
        {
            return false;
        }
        
        FrameworkContentElement parentFCE;
        FrameworkElement parentFE;
        if (!skipStart)
        {
            parentFE = startNode;
            parentFCE = null;
            if (callback(parentFE, parentFCE, in out data))
            {
                return true;
            }
        }
        bool hasParent = FrameworkElement.GetFrameworkParent(startNode, out parentFE, out parentFCE);
        while (hasParent)
        {
            if (callback(parentFE, parentFCE, in out data))
            {
                return true;
            }
 
            // No boundary or inheritance node found, continue search
            if (parentFE != null)
            {
                hasParent = GetFrameworkParent(parentFE, out parentFE, out parentFCE);                           
            }
            else
            {
                hasParent = GetFrameworkParent(parentFCE, out parentFE, out parentFCE);
            }
        }
 
        return false;
    }
 
    /// <summary>
    //  fill this in
    /// </summary>
    public static bool WalkUpLogicalTree(FrameworkContentElement startNode, ParentTraversalCallback callback, bool skipStart, in out object data)
    {
        if (callback == null)
        {
            return false;
        }
        
        FrameworkContentElement parentFCE;
        FrameworkElement parentFE;
        if (!skipStart)
        {
            parentFE = null;
            parentFCE = startNode;
            if (callback(parentFE, parentFCE, in out data))
            {
                return true;
            }
        }
        bool hasParent = FrameworkElement.GetFrameworkParent(startNode, out parentFE, out parentFCE);
        while (hasParent)
        {
            if (callback(parentFE, parentFCE, in out data))
            {
                return true;
            }
 
            // No boundary or inheritance node found, continue search
            if (parentFE != null)
            {
                hasParent = GetFrameworkParent(parentFE, out parentFE, out parentFCE);                           
            }
            else
            {
                hasParent = GetFrameworkParent(parentFCE, out parentFE, out parentFCE);
            }
        }
 
        return false;
    }
 
    /// <summary>
    //  fill this in
    /// </summary>
    public static bool WalkDownLogicalTree(FrameworkElement startNode, ChildTraversalCallback callback, bool skipStart, object data)
    {
        //  use descendants walker here
    }
    
    /// <summary>
    //  fill this in
    /// </summary>
    public static void WalkDownLogicalTree(FrameworkContentElement startNode, ChildTraversalCallback callback, bool skipStart, object data)
    {
        //  use descendants walker here
    }
*/    
    #endregion Public Methods
 
    //------------------------------------------------------
    //
    //  Public Events
    //
    //------------------------------------------------------
 
    // None
 
    //------------------------------------------------------
    //
    //  Internal Constructors
    //
    //------------------------------------------------------
 
    // None
 
    //------------------------------------------------------
    //
    //  Internal Properties
    //
    //------------------------------------------------------
 
    // None
    
    //------------------------------------------------------
    //
    //  Internal Methods
    //
    //------------------------------------------------------
 
    #region Internal Methods
 
    internal static void AddLogicalChild(DependencyObject parent, object child)
    {
        if (child != null && parent != null)
        {
            FrameworkElement parentFE = parent as FrameworkElement;
            if (parentFE != null)
            {
                parentFE.AddLogicalChild(child);
            }
            else
            {
                FrameworkContentElement parentFCE = parent as FrameworkContentElement;
                if (parentFCE != null)
                {
                    parentFCE.AddLogicalChild(child);
                }
            }
        }
    }
 
    internal static void AddLogicalChild(FrameworkElement parentFE, FrameworkContentElement parentFCE, object child)
    {
        if (child != null)
        {
            if (parentFE != null)
            {
                parentFE.AddLogicalChild(child);
            }
            else if (parentFCE != null)
            {
                parentFCE.AddLogicalChild(child);
            }
        }
    }
 
    internal static void RemoveLogicalChild(DependencyObject parent, object child)
    {
        if (child != null && parent != null)
        {
            FrameworkElement parentFE = parent as FrameworkElement;
            if (parentFE != null)
            {
                parentFE.RemoveLogicalChild(child);
            }
            else
            {
                FrameworkContentElement parentFCE = parent as FrameworkContentElement;
                if (parentFCE != null)
                {
                    parentFCE.RemoveLogicalChild(child);
                }
            }
        }
    }
 
    internal static void RemoveLogicalChild(FrameworkElement parentFE, FrameworkContentElement parentFCE, object child)
    {
        if (child != null)
        {
            Debug.Assert(parentFE != null || parentFCE != null, "Either parentFE or parentFCE should be non-null");
            if (parentFE != null)
            {
                parentFE.RemoveLogicalChild(child);
            }
            else
            {
                parentFCE.RemoveLogicalChild(child);
            }
        }
    }
 
    internal static IEnumerator GetLogicalChildren(DependencyObject current)
    {
        FrameworkElement fe = current as FrameworkElement;
        if (fe != null)
        {
            return fe.LogicalChildren;
        }
 
        FrameworkContentElement fce = current as FrameworkContentElement;
        if (fce != null)
        {
            return fce.LogicalChildren;
        }
 
        return MS.Internal.Controls.EmptyEnumerator.Instance;
    }
 
    #endregion Internal Methods
 
    //------------------------------------------------------
    //
    //  Internal Events
    //
    //------------------------------------------------------
 
    // None
 
    //------------------------------------------------------
    //
    //  Private Classes
    //
    //------------------------------------------------------
 
    private class EnumeratorWrapper : IEnumerable
    {
        public EnumeratorWrapper(IEnumerator enumerator)
        {
            if (enumerator != null)
            {
                _enumerator = enumerator;
            }
            else
            {
                _enumerator = MS.Internal.Controls.EmptyEnumerator.Instance;
            }
        }
 
        IEnumerator IEnumerable.GetEnumerator()
        {
            return _enumerator;
        }
 
        IEnumerator _enumerator;
 
 
        internal static EnumeratorWrapper Empty
        {
            get
            {
                if (_emptyInstance == null)
                {
                    _emptyInstance = new EnumeratorWrapper(null);
                }
 
                return _emptyInstance;
            }
        }
 
        static EnumeratorWrapper _emptyInstance;
    }
}
}