using System.Collections.Generic; using System.Linq; using System.Windows; using System.Windows.Controls; using System.Windows.Input; using System.Windows.Media; namespace AIStudio.Wpf.DiagramDesigner { public static class ControlExtession { #region TreeView操作扩展方法 //code:http://www.codeproject.com/Articles/36193/WPF-TreeView-tools /// /// Returns the TreeViewItem of a data bound object. /// /// TreeView /// Data bound object /// The TreeViewItem of the data bound object or null. public static TreeViewItem GetItemFromObject(this TreeView treeView, object obj) { try { DependencyObject dObject = GetContainerFormObject(treeView, obj); TreeViewItem tvi = dObject as TreeViewItem; while (tvi == null) { dObject = VisualTreeHelper.GetParent(dObject); tvi = dObject as TreeViewItem; } return tvi; } catch { } return null; } private static DependencyObject GetContainerFormObject(ItemsControl item, object obj) { if (item == null) return null; DependencyObject dObject = null; dObject = item.ItemContainerGenerator.ContainerFromItem(obj); if (dObject != null) return dObject; var query = from childItem in item.Items.Cast() let childControl = item.ItemContainerGenerator.ContainerFromItem(childItem) as ItemsControl select GetContainerFormObject(childControl, obj); return query.FirstOrDefault(i => i != null); } /// /// Selects a data bound object of a TreeView. /// /// TreeView /// Data bound object public static void SelectObject(this TreeView treeView, object obj) { treeView.SelectObject(obj, true); } /// /// Selects or deselects a data bound object of a TreeView. /// /// TreeView /// Data bound object /// select or deselect public static void SelectObject(this TreeView treeView, object obj, bool selected) { var tvi = treeView.GetItemFromObject(obj); if (tvi != null) { tvi.IsSelected = selected; } } /// /// Returns if a data bound object of a TreeView is selected. /// /// TreeView /// Data bound object /// Returns true if the object is selected, and false if it is not selected or obj is not in the tree. public static bool IsObjectSelected(this TreeView treeView, object obj) { var tvi = treeView.GetItemFromObject(obj); if (tvi != null) { return tvi.IsSelected; } return false; } /// /// Returns if a data bound object of a TreeView is focused. /// /// TreeView /// Data bound object /// Returns true if the object is focused, and false if it is not focused or obj is not in the tree. public static bool IsObjectFocused(this TreeView treeView, object obj) { var tvi = treeView.GetItemFromObject(obj); if (tvi != null) { return tvi.IsFocused; } return false; } /// /// Expands a data bound object of a TreeView. /// /// TreeView /// Data bound object public static void ExpandObject(this TreeView treeView, object obj) { treeView.ExpandObject(obj, true); } /// /// Expands or collapses a data bound object of a TreeView. /// /// TreeView /// Data bound object /// expand or collapse public static void ExpandObject(this TreeView treeView, object obj, bool expanded) { var tvi = treeView.GetItemFromObject(obj); if (tvi != null) { tvi.IsExpanded = expanded; if (expanded) { // update layout, so that following calls to f.e. SelectObject on child nodes will // find theire TreeViewNodes treeView.UpdateLayout(); } } } /// /// Returns if a douta bound object of a TreeView is expanded. /// /// TreeView /// Data bound object /// Returns true if the object is expanded, and false if it is collapsed or obj is not in the tree. public static bool IsObjectExpanded(this TreeView treeView, object obj) { var tvi = treeView.GetItemFromObject(obj); if (tvi != null) { return tvi.IsExpanded; } return false; } /// /// Retuns the parent TreeViewItem. /// /// TreeViewItem /// Parent TreeViewItem public static TreeViewItem GetParentItem(this TreeViewItem item) { var dObject = VisualTreeHelper.GetParent(item); TreeViewItem tvi = dObject as TreeViewItem; while (tvi == null) { dObject = VisualTreeHelper.GetParent(dObject); tvi = dObject as TreeViewItem; } return tvi; } #endregion #region FindParent/FindChildren /// /// Finds a parent of a given item on the visual tree. /// /// The type of the queried item. /// A direct or indirect child of the /// queried item. /// The first parent item that matches the submitted /// type parameter. If not matching item can be found, a null /// reference is being returned. public static T TryFindParent(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; return parent ?? TryFindParent(parentObject); } //public static T FindParent(DependencyObject child) where T : DependencyObject //{ // //get parent item // var parentObject = VisualTreeHelper.GetParent(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 // var parent = parentObject as T; // return parent ?? FindParent(parentObject); //} /// /// Finds a Child of a given item in the visual tree. /// /// A direct parent of the queried item. /// The type of the queried item. /// x:Name or Name of child. /// The first parent item that matches the submitted type parameter. /// If not matching item can be found, /// a null parent is being returned. public static T FindChild(this 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(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; } /// /// This method is an alternative to WPF's /// method, which also /// supports content elements. Keep in mind that for content element, /// this method falls back to the logical tree of the element! /// /// The item to be processed. /// The submitted item's parent, if available. Otherwise /// null. public static DependencyObject GetParentObject(this DependencyObject child) { if (child == null) return null; //handle content elements separately var contentElement = child as ContentElement; if (contentElement != null) { DependencyObject parent = ContentOperations.GetParent(contentElement); if (parent != null) return parent; var fce = contentElement as FrameworkContentElement; return fce != null ? fce.Parent : null; } //also try searching for parent in framework elements (such as DockPanel, etc) var 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); } /// /// Analyzes both visual and logical tree in order to find all elements of a given /// type that are descendants of the item. /// /// The type of the queried items. /// 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. /// Sometimes it's better to search in the VisualTree (e.g. in tests) /// All descendants of that match the requested type. public static IEnumerable FindChildren(this DependencyObject source, bool forceUsingTheVisualTreeHelper = false) where T : DependencyObject { if (source != null) { var childs = GetChildObjects(source, forceUsingTheVisualTreeHelper); foreach (DependencyObject child in childs) { //analyze if children match the requested type if (child != null && child is T) { yield return (T)child; } //recurse tree foreach (T descendant in FindChildren(child)) { yield return descendant; } } } } /// /// This method is an alternative to WPF's /// method, which also /// supports content elements. Keep in mind that for content elements, /// this method falls back to the logical tree of the element. /// /// The item to be processed. /// Sometimes it's better to search in the VisualTree (e.g. in tests) /// The submitted item's child elements, if available. public static IEnumerable GetChildObjects(this DependencyObject parent, bool forceUsingTheVisualTreeHelper = false) { if (parent == null) yield break; if (!forceUsingTheVisualTreeHelper && (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); } } } /// /// Tries to locate a given item within the visual tree, /// starting with the dependency object at a given _position. /// /// The type of the element to be found /// on the visual tree of the element at the given location. /// The main element which is used to perform /// hit testing. /// The _position to be evaluated on the origin. public static T TryFindFromPoint(UIElement reference, Point point) where T : DependencyObject { var element = reference.InputHitTest(point) as DependencyObject; if (element == null) return null; if (element is T) return (T)element; return TryFindParent(element); //DependencyObject hitObject = reference.InputHitTest(point) as DependencyObject; //while (hitObject != null && // hitObject.GetType() != typeof(DesignerCanvas)) //{ // if (hitObject is T) // { // return (T)hitObject; // } // hitObject = VisualTreeHelper.GetParent(hitObject); //} //return null; } #endregion } }