确定 UIElementCollection 的父级

Determining the parent of a UIElementCollection

我想知道是否有任何方法可以确定 UIElementCollection 的 Parent 是否为 Grid 类型,最好使用反射。

UIElementCollection 是一个 WPF 对象,例如用于 Grid 中的 Children。 Class定义:

public class UIElementCollection : IList, ICollection, IEnumerable

网格class定义:

public class Grid : Panel, IAddChild

面板class定义:

public abstract class Panel : FrameworkElement, IAddChild
{
    public UIElementCollection Children { get; }
    // Bunch of other members...
}

编辑: 当前的错误代码:

        string visualParent = "";
        if (collection.Count == 0)
        {
            collection.Add(element);
            visualParent = VisualTreeHelper.GetParent(collection[0]).ToString();
            collection.Remove(element);
        }
        else
        {
            visualParent = VisualTreeHelper.GetParent(collection[0]).ToString();
        }

        if (!visualParent.Contains("Grid"))
        {
            throw new ArgumentException("The UIElementCollection's Parent is not a Grid. Please provide a Grid.Children UIElementCollection.");
        }

这里不需要反射。您可以使用 the is operator 清理此代码,它可以检测有效的向下转换,例如从 DependencyObject 到 Grid。您可以通过使用专用于此父级检测操作的 UIElement 来消除一些 if 语句(这意味着一个元素从未用于任何其他用途)。考虑:

var idx = collection.Add(parentDetectionElement);
var isGrid = VisualTreeHelper.GetParent(collection[idx]) is Grid;
collection.RemoveAt(idx);
if(!isGrid)
{ 
    throw new ArgumentException("The UIElementCollection's Parent is not a Grid. Please provide a Grid.Children UIElementCollection.");
}

这更加简洁,避免了混乱和可能有错误的字符串操作,并且它不再依赖于检查集合。但是,使用专用元素实例执行此操作很重要,以确保它不会已经在集合的大小中。如果将其封装在函数中,则可以在本地声明一个新的 UIElement 并确保这一点。此外,封装改进了您的控制流选项;如果需要,您可以 return 一个布尔值来指示父级是否为 Grid,而不是抛出异常。

如果您打算使用反射,那么您可以检查不可访问的 属性,它保存了视觉父对象的引用。根据the UIElementCollection source code,是UIElement类型的VisualParent。找到它后,您可以检查类型,如上所示。请注意,VisualParent 的访问修饰符是内部的,class 打开 MS.Internal 命名空间。这就是 CLR 可以检测父类型的原因:他们明确设计 class 以允许一般消费者禁止的 Microsoft 代码功能。