diff options
| author | LukePulverenti <luke.pulverenti@gmail.com> | 2013-02-20 20:33:05 -0500 |
|---|---|---|
| committer | LukePulverenti <luke.pulverenti@gmail.com> | 2013-02-20 20:33:05 -0500 |
| commit | 767cdc1f6f6a63ce997fc9476911e2c361f9d402 (patch) | |
| tree | 49add55976f895441167c66cfa95e5c7688d18ce /MediaBrowser.UI.Controls/TreeHelper.cs | |
| parent | 845554722efaed872948a9e0f7202e3ef52f1b6e (diff) | |
Pushing missing changes
Diffstat (limited to 'MediaBrowser.UI.Controls/TreeHelper.cs')
| -rw-r--r-- | MediaBrowser.UI.Controls/TreeHelper.cs | 321 |
1 files changed, 321 insertions, 0 deletions
diff --git a/MediaBrowser.UI.Controls/TreeHelper.cs b/MediaBrowser.UI.Controls/TreeHelper.cs new file mode 100644 index 000000000..0347f1eba --- /dev/null +++ b/MediaBrowser.UI.Controls/TreeHelper.cs @@ -0,0 +1,321 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Windows; +using System.Windows.Media; + +namespace MediaBrowser.UI.Controls +{ + /// <summary> + /// Helper methods for UI-related tasks. + /// </summary> + public static class TreeHelper + { + /// <summary> + /// Gets the window. + /// </summary> + /// <param name="element">The element.</param> + /// <returns>Window.</returns> + /// <value>The window.</value> + public static Window GetWindow(this FrameworkElement element) + { + return element.ParentOfType<Window>(); + } + + /// <summary> + /// Gets the parent. + /// </summary> + /// <param name="element">The element.</param> + /// <returns>DependencyObject.</returns> + private static DependencyObject GetParent(this DependencyObject element) + { + DependencyObject parent = VisualTreeHelper.GetParent(element); + if (parent == null) + { + FrameworkElement frameworkElement = element as FrameworkElement; + if (frameworkElement != null) + { + parent = frameworkElement.Parent; + } + } + return parent; + } + + /// <summary> + /// Gets the parents. + /// </summary> + /// <param name="element">The element.</param> + /// <returns>IEnumerable{DependencyObject}.</returns> + /// <exception cref="System.ArgumentNullException">element</exception> + public static IEnumerable<DependencyObject> GetParents(this DependencyObject element) + { + if (element == null) + { + throw new ArgumentNullException("element"); + } + while ((element = element.GetParent()) != null) + { + yield return element; + } + yield break; + } + + /// <summary> + /// Parents the type of the of. + /// </summary> + /// <typeparam name="T"></typeparam> + /// <param name="element">The element.</param> + /// <returns>``0.</returns> + public static T ParentOfType<T>(this DependencyObject element) where T : DependencyObject + { + if (element == null) + { + return default(T); + } + return element.GetParents().OfType<T>().FirstOrDefault<T>(); + } + + /// <summary> + /// Finds a Child of a given item in the visual tree. + /// </summary> + /// <typeparam name="T">The type of the queried item.</typeparam> + /// <param name="parent">A direct parent of the queried item.</param> + /// <param name="childName">x:Name or Name of child.</param> + /// <returns>The first parent item that matches the submitted type parameter. + /// If not matching item can be found, + /// a null parent is being returned.</returns> + public static T FindChild<T>(DependencyObject parent, string childName) + where T : DependencyObject + { + // Confirm parent and childName are valid. + if (parent == null) return null; + + T foundChild = null; + + int childrenCount = VisualTreeHelper.GetChildrenCount(parent); + for (int i = 0; i < childrenCount; i++) + { + var child = VisualTreeHelper.GetChild(parent, i); + // If the child is not of the request child type child + T childType = child as T; + if (childType == null) + { + // recursively drill down the tree + foundChild = FindChild<T>(child, childName); + + // If the child is found, break so we do not overwrite the found child. + if (foundChild != null) break; + } + else if (!string.IsNullOrEmpty(childName)) + { + var frameworkElement = child as FrameworkElement; + // If the child's name is set for search + if (frameworkElement != null && frameworkElement.Name == childName) + { + // if the child's name is of the request name + foundChild = (T)child; + break; + } + } + else + { + // child element found. + foundChild = (T)child; + break; + } + } + + return foundChild; + } + + /// <summary> + /// Gets the visual child. + /// </summary> + /// <typeparam name="T"></typeparam> + /// <param name="referenceVisual">The reference visual.</param> + /// <returns>``0.</returns> + public static T GetVisualChild<T>(this Visual referenceVisual) where T : Visual + { + Visual child = null; + for (Int32 i = 0; i < VisualTreeHelper.GetChildrenCount(referenceVisual); i++) + { + child = VisualTreeHelper.GetChild(referenceVisual, i) as Visual; + if (child != null && (child.GetType() == typeof(T))) + { + break; + } + else if (child != null) + { + child = GetVisualChild<T>(child); + if (child != null && (child.GetType() == typeof(T))) + { + break; + } + } + } + return child as T; + } + + #region find parent + + /// <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 not matching item can be found, a null + /// reference is being returned.</returns> + public static T TryFindParent<T>(this DependencyObject child) + where T : DependencyObject + { + //get parent item + DependencyObject parentObject = GetParentObject(child); + + //we've reached the end of the tree + if (parentObject == null) return null; + + //check if the parent matches the type we're looking for + T parent = parentObject as T; + if (parent != null) + { + return parent; + } + + //use recursion to proceed with next level + return TryFindParent<T>(parentObject); + } + + /// <summary> + /// 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> + public 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) + { + DependencyObject parent = frameworkElement.Parent; + if (parent != null) return parent; + } + + //if it's not a ContentElement/FrameworkElement, rely on VisualTreeHelper + return VisualTreeHelper.GetParent(child); + } + + #endregion + + #region find children + + /// <summary> + /// Analyzes both visual and logical tree in order to find all elements of a given + /// type that are descendants of the <paramref name="source" /> item. + /// </summary> + /// <typeparam name="T">The type of the queried items.</typeparam> + /// <param name="source">The root element that marks the source of the search. If the + /// source is already of the requested type, it will not be included in the result.</param> + /// <returns>All descendants of <paramref name="source" /> that match the requested type.</returns> + public static IEnumerable<T> FindChildren<T>(this DependencyObject source) where T : DependencyObject + { + if (source != null) + { + var childs = GetChildObjects(source); + foreach (DependencyObject child in childs) + { + //analyze if children match the requested type + if (child is T) + { + yield return (T)child; + } + + //recurse tree + foreach (T descendant in FindChildren<T>(child)) + { + yield return descendant; + } + } + } + } + + + /// <summary> + /// This method is an alternative to WPF's + /// <see cref="VisualTreeHelper.GetChild" /> method, which also + /// supports content elements. Keep in mind that for content elements, + /// this method falls back to the logical tree of the element. + /// </summary> + /// <param name="parent">The item to be processed.</param> + /// <returns>The submitted item's child elements, if available.</returns> + public static IEnumerable<DependencyObject> GetChildObjects(this DependencyObject parent) + { + if (parent == null) yield break; + + if (parent is ContentElement || parent is FrameworkElement) + { + //use the logical tree for content / framework elements + foreach (object obj in LogicalTreeHelper.GetChildren(parent)) + { + var depObj = obj as DependencyObject; + if (depObj != null) yield return (DependencyObject)obj; + } + } + else + { + //use the visual tree per default + int count = VisualTreeHelper.GetChildrenCount(parent); + for (int i = 0; i < count; i++) + { + yield return VisualTreeHelper.GetChild(parent, i); + } + } + } + + #endregion + + #region find from point + + /// <summary> + /// Tries to locate a given item within the visual tree, + /// starting with the dependency object at a given position. + /// </summary> + /// <typeparam name="T">The type of the element to be found + /// on the visual tree of the element at the given location.</typeparam> + /// <param name="reference">The main element which is used to perform + /// hit testing.</param> + /// <param name="point">The position to be evaluated on the origin.</param> + /// <returns>``0.</returns> + public static T TryFindFromPoint<T>(UIElement reference, Point point) + where T : DependencyObject + { + DependencyObject element = reference.InputHitTest(point) as DependencyObject; + + if (element == null) return null; + + if (element is T) return (T)element; + + return TryFindParent<T>(element); + } + + #endregion + } +} |
