Найти все элементы управления в окне WPF по типу - PullRequest
205 голосов
/ 10 июня 2009

Я ищу способ найти все элементы управления в Window по их типу,

например: найти все TextBoxes, найти все элементы управления, реализующие определенный интерфейс и т. Д.

Ответы [ 16 ]

404 голосов
/ 11 июня 2009

Это должно сработать

public static IEnumerable<T> FindVisualChildren<T>(DependencyObject depObj) where T : DependencyObject
{
    if (depObj != null)
    {
        for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
        {
            DependencyObject child = VisualTreeHelper.GetChild(depObj, i);
            if (child != null && child is T)
            {
                yield return (T)child;
            }

            foreach (T childOfChild in FindVisualChildren<T>(child))
            {
                yield return childOfChild;
            }
        }
    }
}

тогда вы перечисляете элементы управления вот так

foreach (TextBlock tb in FindVisualChildren<TextBlock>(window))
{
    // do something with tb here
}
60 голосов
/ 11 июня 2009

Это самый простой способ:

IEnumerable<myType> collection = control.Children.OfType<myType>(); 

где control - корневой элемент окна.

19 голосов
/ 23 мая 2014

Я адаптировал ответ @Bryce Kahle, чтобы следовать предложению @Mathias Lykkegaard Lorenzen и использовать LogicalTreeHelper.

Кажется, работает хорошо. ;)

    public static IEnumerable<T> FindLogicalChildren<T> ( DependencyObject depObj ) where T : DependencyObject {
        if( depObj != null ) {
            foreach( object rawChild in LogicalTreeHelper.GetChildren( depObj ) ){
                if( rawChild is DependencyObject ) {
                    DependencyObject child = (DependencyObject)rawChild;
                    if( child is T ) {
                        yield return (T)child;
                    }

                    foreach( T childOfChild in FindLogicalChildren<T>( child ) ) {
                        yield return childOfChild;
                    }
                }
            }
        }
    }

(Он по-прежнему не будет проверять элементы управления вкладками или сетки внутри групповых ящиков, как указано @Benjamin Berry & @David R соответственно.) (Также следовал совету @ noonand и удалил лишнего ребенка! = Null)

11 голосов
/ 10 июня 2009

Используйте вспомогательные классы VisualTreeHelper или LogicalTreeHelper в зависимости от того, какое дерево вас интересует. Они оба предоставляют методы для получения дочерних элементов (хотя синтаксис немного отличается). Я часто использую эти классы для нахождения первого вхождения определенного типа, но вы можете легко изменить его, чтобы найти все объекты этого типа:

public static DependencyObject FindInVisualTreeDown(DependencyObject obj, Type type)
{
    if (obj != null)
    {
        if (obj.GetType() == type)
        {
            return obj;
        }

        for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++)
        {
            DependencyObject childReturn = FindInVisualTreeDown(VisualTreeHelper.GetChild(obj, i), type);
            if (childReturn != null)
            {
                return childReturn;
            }
        }
    }

    return null;
}
9 голосов
/ 23 августа 2011

Я обнаружил, что строка VisualTreeHelper.GetChildrenCount (depObj);, используемая в нескольких приведенных выше примерах, не возвращает ненулевой счет для GroupBoxes, в частности, где GroupBox содержит Grid, а Grid содержит дочерние элементы. Я полагаю, что это может быть связано с тем, что GroupBox не может содержать более одного дочернего элемента, и это хранится в его свойстве Content. Тип собственности GroupBox.Children отсутствует. Я уверен, что сделал это не очень эффективно, но я изменил первый пример «FindVisualChildren» в этой цепочке следующим образом:

    public IEnumerable<T> FindVisualChildren<T>(DependencyObject depObj) where T : DependencyObject 
    { 
        if (depObj != null) 
        {
            int depObjCount = VisualTreeHelper.GetChildrenCount(depObj); 
            for (int i = 0; i <depObjCount; i++) 
            { 
                DependencyObject child = VisualTreeHelper.GetChild(depObj, i); 
                if (child != null && child is T) 
                { 
                    yield return (T)child; 
                }

                if (child is GroupBox)
                {
                    GroupBox gb = child as GroupBox;
                    Object gpchild = gb.Content;
                    if (gpchild is T)
                    {
                        yield return (T)child; 
                        child = gpchild as T;
                    }
                }

                foreach (T childOfChild in FindVisualChildren<T>(child)) 
                { 
                    yield return childOfChild; 
                } 
            }
        }
    } 
4 голосов
/ 08 сентября 2012

Небольшое изменение в рекурсии, чтобы вы могли, например, найти дочерний элемент управления вкладки элемента управления вкладкой.

    public static DependencyObject FindInVisualTreeDown(DependencyObject obj, Type type)
    {
        if (obj != null)
        {
            for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++)
            {
                DependencyObject child = VisualTreeHelper.GetChild(obj, i);

                if (child.GetType() == type)
                {
                    return child;
                }

                DependencyObject childReturn = FindInVisualTreeDown(child, type);
                if (childReturn != null)
                {
                    return childReturn;
                }
            }
        }

        return null;
    }
4 голосов
/ 21 апреля 2010

Чтобы получить список всех потомков определенного типа, вы можете использовать:

private static IEnumerable<DependencyObject> FindInVisualTreeDown(DependencyObject obj, Type type)
{
    if (obj != null)
    {
        if (obj.GetType() == type)
        {
            yield return obj;
        }

        for (var i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++)
        {
            foreach (var child in FindInVisualTreeDown(VisualTreeHelper.GetChild(obj, i), type))
            {
                if (child != null)
                {
                    yield return child;
                }
            }
        }
    }

    yield break;
}
2 голосов
/ 06 мая 2015

Вот еще одна компактная версия с общим синтаксисом:

    public static IEnumerable<T> FindLogicalChildren<T>(DependencyObject obj) where T : DependencyObject
    {
        if (obj != null) {
            if (obj is T)
                yield return obj as T;

            foreach (DependencyObject child in LogicalTreeHelper.GetChildren(obj).OfType<DependencyObject>()) 
                foreach (T c in FindLogicalChildren<T>(child)) 
                    yield return c;
        }
    }
2 голосов
/ 25 июня 2009

Обратите внимание, что использование VisualTreeHelper работает только с элементами управления, которые являются производными от Visual или Visual3D. Если вам также необходимо проверить другие элементы (например, TextBlock, FlowDocument и т. Д.), Использование VisualTreeHelper вызовет исключение.

Вот альтернатива, которая при необходимости возвращается к логическому дереву:

http://www.hardcodet.net/2009/06/finding-elements-in-wpf-tree-both-ways

2 голосов
/ 10 июня 2009

А вот как это работает вверх

    private T FindParent<T>(DependencyObject item, Type StopAt) where T : class
    {
        if (item is T)
        {
            return item as T;
        }
        else
        {
            DependencyObject _parent = VisualTreeHelper.GetParent(item);
            if (_parent == null)
            {
                return default(T);
            }
            else
            {
                Type _type = _parent.GetType();
                if (StopAt != null)
                {
                    if ((_type.IsSubclassOf(StopAt) == true) || (_type == StopAt))
                    {
                        return null;
                    }
                }

                if ((_type.IsSubclassOf(typeof(T)) == true) || (_type == typeof(T)))
                {
                    return _parent as T;
                }
                else
                {
                    return FindParent<T>(_parent, StopAt);
                }
            }
        }
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...