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

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

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

Ответы [ 16 ]

1 голос
/ 09 июня 2019

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

Если вам нужны элементы-потомки в в порядке убывания , где сначала будут получены прямые потомки, затем их потомки и т. Д., То будет работать следующий алгоритм:

public static IEnumerable<T> GetVisualDescendants<T>(DependencyObject parent, bool applyTemplates = false)
    where T : DependencyObject
{
    if (parent == null || !(child is Visual || child is Visual3D))
        yield break;

    var descendants = new Queue<DependencyObject>();
    descendants.Enqueue(parent);

    while (descendants.Count > 0)
    {
        var currentDescendant = descendants.Dequeue();

        if (applyTemplates)
            (currentDescendant as FrameworkElement)?.ApplyTemplate();

        for (var i = 0; i < VisualTreeHelper.GetChildrenCount(currentDescendant); i++)
        {
            var child = VisualTreeHelper.GetChild(currentDescendant, i);

            if (child is Visual || child is Visual3D)
                descendants.Enqueue(child);

            if (child is T foundObject)
                yield return foundObject;
        }
    }
}

Полученные элементы будут упорядочены от ближайшего к дальнему. Это будет полезно, например, если вы ищете ближайший дочерний элемент какого-либо типа и условия:

var foundElement = GetDescendants<StackPanel>(someElement)
                       .FirstOrDefault(o => o.SomeProperty == SomeState);
1 голос
/ 14 сентября 2016

По какой-то причине ни один из ответов, опубликованных здесь, не помог мне получить все элементы управления данного типа, содержащиеся в данном элементе управления, в моем главном окне. Мне нужно было найти все пункты меню в одном меню, чтобы перебрать их. Все они не были прямыми потомками меню, поэтому мне удалось собрать только первые из них, используя любой из приведенных выше кодов. Этот метод расширения является моим решением проблемы для любого, кто продолжит читать все здесь.

public static void FindVisualChildren<T>(this ICollection<T> children, DependencyObject depObj) where T : DependencyObject
    {
        if (depObj != null)
        {
            var brethren = LogicalTreeHelper.GetChildren(depObj);
            var brethrenOfType = LogicalTreeHelper.GetChildren(depObj).OfType<T>();
            foreach (var childOfType in brethrenOfType)
            {
                children.Add(childOfType);
            }

            foreach (var rawChild in brethren)
            {
                if (rawChild is DependencyObject)
                {
                    var child = rawChild as DependencyObject;
                    FindVisualChildren<T>(children, child);
                }
            }
        }
    }

Надеюсь, это поможет.

1 голос
/ 26 марта 2016

Моя версия для C ++ / CLI

template < class T, class U >
bool Isinst(U u) 
{
    return dynamic_cast< T >(u) != nullptr;
}

template <typename T>
    T FindVisualChildByType(Windows::UI::Xaml::DependencyObject^ element, Platform::String^ name)
    {
        if (Isinst<T>(element) && dynamic_cast<Windows::UI::Xaml::FrameworkElement^>(element)->Name == name)
        {
            return dynamic_cast<T>(element);
        }
        int childcount = Windows::UI::Xaml::Media::VisualTreeHelper::GetChildrenCount(element);
        for (int i = 0; i < childcount; ++i)
        {
            auto childElement = FindVisualChildByType<T>(Windows::UI::Xaml::Media::VisualTreeHelper::GetChild(element, i), name);
            if (childElement != nullptr)
            {
                return childElement;
            }
        }
        return nullptr;
    };
1 голос
/ 02 января 2016

Я хотел добавить комментарий, но у меня меньше 50 баллов, поэтому я могу только "Ответить". Имейте в виду, что если вы используете метод «VisualTreeHelper» для извлечения объектов XAML «TextBlock», то он также будет захватывать объекты «кнопки» XAML. Если вы повторно инициализируете объект «TextBlock» путем записи в параметр Textblock.Text, вы больше не сможете изменять текст Button с помощью параметра Button.Content. Кнопка будет постоянно показывать текст, записанный в нее из действия записи Textblock.Text (с момента, когда он был извлечен -

foreach (TextBlock tb in FindVisualChildren<TextBlock>(window))
{
// do something with tb here
   tb.Text = ""; //this will overwrite Button.Content and render the 
                 //Button.Content{set} permanently disabled.
}

Чтобы обойти это, вы можете попробовать использовать XAML «TextBox» и добавить методы (или события) для имитации кнопки XAMAL. XAML «TextBox» не собирается поиском «TextBlock».

0 голосов
/ 11 июня 2017

Действительно хороший ответ.

VB.NET версия:

Public Shared Iterator Function FindVisualChildren(Of T As DependencyObject)(depObj As DependencyObject) As IEnumerable(Of T)
    If depObj IsNot Nothing Then
        For i As Integer = 0 To VisualTreeHelper.GetChildrenCount(depObj) - 1
            Dim child As DependencyObject = VisualTreeHelper.GetChild(depObj, i)
            If child IsNot Nothing AndAlso TypeOf child Is T Then
                Yield DirectCast(child, T)
            End If
            For Each childOfChild As T In FindVisualChildren(Of T)(child)
                Yield childOfChild
            Next
        Next
    End If
End Function

Использование (это отключает все текстовые поля в окне):

        For Each tb As TextBox In FindVisualChildren(Of TextBox)(Me)
          tb.IsEnabled = False
        Next
0 голосов
/ 17 марта 2016

Мне было проще без помощников Visual Tree:

foreach (UIElement element in MainWindow.Children) {
    if (element is TextBox) { 
        if ((element as TextBox).Text != "")
        {
            //Do something
        }
    }
};
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...