我正在寻找一种方法,通过它们的类型在窗口上找到所有控件,

例如:找到所有的文本框,找到所有实现特定界面的控件等。


当前回答

这应该可以达到目的:

public static IEnumerable<T> FindVisualChilds<T>(DependencyObject depObj) where T : DependencyObject
{
    if (depObj == null) yield return (T)Enumerable.Empty<T>();
    for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
    {
        DependencyObject ithChild = VisualTreeHelper.GetChild(depObj, i);
        if (ithChild == null) continue;
        if (ithChild is T t) yield return t;
        foreach (T childOfChild in FindVisualChilds<T>(ithChild)) yield return childOfChild;
    }
}

然后像这样枚举控件

foreach (TextBlock tb in FindVisualChildren<TextBlock>(window))
{
    // do something with tb here
}

其他回答

出于某种原因,这里发布的答案都没有帮助我在主窗口中获得给定控件中包含的给定类型的所有控件。 我需要在一个菜单中找到所有的菜单项来迭代它们。它们并不都是菜单的直接后代,所以我使用上面的任何代码只收集了它们的第一行。 这个扩展方法是我对这个问题的解决方案,任何人都将继续读到这里。

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);
                }
            }
        }
    }

希望能有所帮助。

对递归做了一点小小的改变,例如,你可以找到一个标签控件的子标签控件。

    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;
    }

请注意,使用VisualTreeHelper仅适用于派生自Visual或Visual3D的控件。如果你还需要检查其他元素(例如TextBlock, FlowDocument等),使用VisualTreeHelper将抛出一个异常。

如果有必要,这里有一个回到逻辑树的替代方案:

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

@Bryce,回答得很好。

VB。净版:

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

这是最简单的方法:

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

其中控件是窗口的根元素。

编辑-正如评论中指出的那样。这只是一个层次的深度。查看一个更深入的选项的公认答案。