按类型查找控件的祖先

mca*_*lex 1 c# wpf visualtreehelper

UserControl在另一个中有一个“子项” UserControl(它充当 a 中的 TabItem TabControl)。在子项UserControl和 TabItem 祖先之间是许多其他控件(例如:Grids、 a StackPanel,可能是 aScrollViewer等)。

UserControl我想访问我的孩子中TabItem 的属性UserControl,并自定义一个通常 建议的递归函数,该函数沿着可视化树向上移动。但是,这总是在第一次空检查时返回true,直到我在逻辑树上添加查询。

代码:

public MyTabItem FindParentTabItem(DependencyObject child)
{
  DependencyObject parent = VisualTreeHelper.GetParent(child) ?? LogicalTreeHelper.GetParent(child);

  // are we at the top of the tree
  if (parent == null)
  {
      return null;
  }
  MyTabItem parentTabItem = parent as MyTabItem;
  if (parentTabItem != null)
  {
    return parentTabItem;
  }
  else
  {
    //use recursion until it reaches the control
    return FindParentTabItem(parent);
  }
}
Run Code Online (Sandbox Code Playgroud)

不幸的是,这也返回 null。当单步执行该方法时,我看到它确实找到了正确的UserControlTabItem,但是当它通过返回递归(?)时,它将其恢复为 null,然后返回到调用方法(在 childUserControl的 Loaded 事件中) ):

MyTabItem tab = FindParentTabItem(this);
Run Code Online (Sandbox Code Playgroud)

如何解决此问题以便我的方法正确返回找到的结果MyTabItem

Bla*_*pel 5

这是一个经过单元测试的有效解决方案。

public static T FindAncestor<T>(DependencyObject obj)
    where T : DependencyObject
{
    if (obj != null)
    {
        var dependObj = obj;
        do
        {
            dependObj = GetParent(dependObj);
            if (dependObj is T)
                return dependObj as T;
        }
        while (dependObj != null);
    }

    return null;
}

public static DependencyObject GetParent(DependencyObject obj)
{
    if (obj == null)
        return null;
    if (obj is ContentElement)
    {
        var parent = ContentOperations.GetParent(obj as ContentElement);
        if (parent != null)
            return parent;
        if (obj is FrameworkContentElement)
            return (obj as FrameworkContentElement).Parent;
        return null;
    }

    return VisualTreeHelper.GetParent(obj);
}
Run Code Online (Sandbox Code Playgroud)

用法是

FindAncestor<MyTabItemType>(someChild);
Run Code Online (Sandbox Code Playgroud)

编辑:

让我们假设您的 xaml 看起来像您所描述的那样:

public static T FindAncestor<T>(DependencyObject obj)
    where T : DependencyObject
{
    if (obj != null)
    {
        var dependObj = obj;
        do
        {
            dependObj = GetParent(dependObj);
            if (dependObj is T)
                return dependObj as T;
        }
        while (dependObj != null);
    }

    return null;
}

public static DependencyObject GetParent(DependencyObject obj)
{
    if (obj == null)
        return null;
    if (obj is ContentElement)
    {
        var parent = ContentOperations.GetParent(obj as ContentElement);
        if (parent != null)
            return parent;
        if (obj is FrameworkContentElement)
            return (obj as FrameworkContentElement).Parent;
        return null;
    }

    return VisualTreeHelper.GetParent(obj);
}
Run Code Online (Sandbox Code Playgroud)

您当前位于 child-xaml.cs 中

void OnChildUserControlLoaded(object sender, RoutedEventArgs e)
{
    var parent = FindAncestor<ParentUserControlType>(this);
    DoSomething(parent.SomeProperty);
}
Run Code Online (Sandbox Code Playgroud)

除非你做了一些你没有描述的事情,否则代码将按原样工作。
我建议您向MCVE提供所有必要的信息。