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

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


当前回答

下面是另一个紧凑的版本,使用泛型语法:

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

其他回答

这就是它向上的工作原理

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

我根据@Mathias Lykkegaard Lorenzen的建议改编了@Bryce Kahle的回答,并使用了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)

我发现没有Visual Tree Helpers更容易:

foreach (UIElement element in MainWindow.Children) {
    if (element is TextBox) { 
        if ((element as TextBox).Text != "")
        {
            //Do something
        }
    }
};

@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

使用帮助类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;
}