我需要在WPF控件层次结构中搜索与给定名称或类型匹配的控件。我该怎么做呢?


当前回答

您还可以使用FrameworkElement.FindName(string)按名称查找元素。

考虑到:

<UserControl ...>
    <TextBlock x:Name="myTextBlock" />
</UserControl>

在代码隐藏文件中,你可以这样写:

var myTextBlock = (TextBlock)this.FindName("myTextBlock");

当然,因为它是使用x:Name定义的,所以您可以只引用生成的字段,但是您可能希望动态而不是静态地查找它。

这种方法也可用于模板,其中命名项出现多次(每次使用模板一次)。

其他回答

这些选项已经讨论了如何在c#中遍历可视化树。 使用RelativeSource标记扩展也可以遍历xaml中的可视树。msdn

按类型查找

Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type <TypeToFind>}}}" 

如果您希望找到特定类型的ALL控件,那么您可能也会对这个代码段感兴趣

    public static IEnumerable<T> FindVisualChildren<T>(DependencyObject parent) 
        where T : DependencyObject
    {
        int childrenCount = VisualTreeHelper.GetChildrenCount(parent);
        for (int i = 0; i < childrenCount; i++)
        {
            var child = VisualTreeHelper.GetChild(parent, i);

            var childType = child as T;
            if (childType != null)
            {
                yield return (T)child;
            }

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

试试这个

<TextBlock x:Name="txtblock" FontSize="24" >Hai Welcom to this page
</TextBlock>

后面的代码

var txtblock = sender as Textblock;
txtblock.Foreground = "Red"

我找不到@CrimsonX或@Drew Noakes方法的控件,因为我的ControlTemplate位于一个单独的XAML文件中。 我用下面的方法找到了控件:

private Image backImage;
private void Diagram_Loaded(object sender, System.Windows.RoutedEventArgs e)
{
    // here is the example of the ControlTemplate declaration
    //<ControlTemplate x:Key="DiagramControlTemplate1" TargetType="{x:Type Diagram}">
    var ctrlTemplate = (ControlTemplate)FindResource("DiagramControlTemplate1");
    // diagram is the x:Name of TemplatedControl and, "backImage" is the name of control that I want to find.
    var imageControl = ctrlTemplate.FindName("backImage", diagram);
    if (imageControl != null)
    {
        this.backImage = (Image)imageControl;
    }
}

这对我很有用。

exciton80……我有一个问题,你的代码不递归通过用户控件。它击中了网格根并抛出了一个错误。我相信这能解决我的问题:

public static object[] FindControls(this FrameworkElement f, Type childType, int maxDepth)
{
    return RecursiveFindControls(f, childType, 1, maxDepth);
}

private static object[] RecursiveFindControls(object o, Type childType, int depth, int maxDepth = 0)
{
    List<object> list = new List<object>();
    var attrs = o.GetType().GetCustomAttributes(typeof(ContentPropertyAttribute), true);
    if (attrs != null && attrs.Length > 0)
    {
        string childrenProperty = (attrs[0] as ContentPropertyAttribute).Name;
        if (String.Equals(childrenProperty, "Content") || String.Equals(childrenProperty, "Children"))
        {
            var collection = o.GetType().GetProperty(childrenProperty).GetValue(o, null);
            if (collection is System.Windows.Controls.UIElementCollection) // snelson 6/6/11
            {
                foreach (var c in (IEnumerable)collection)
                {
                    if (c.GetType().FullName == childType.FullName)
                        list.Add(c);
                    if (maxDepth == 0 || depth < maxDepth)
                        list.AddRange(RecursiveFindControls(
                            c, childType, depth + 1, maxDepth));
                }
            }
            else if (collection != null && collection.GetType().BaseType.Name == "Panel") // snelson 6/6/11; added because was skipping control (e.g., System.Windows.Controls.Grid)
            {
                if (maxDepth == 0 || depth < maxDepth)
                    list.AddRange(RecursiveFindControls(
                        collection, childType, depth + 1, maxDepth));
            }
        }
    }
    return list.ToArray();
}