获取GridViewColumn的父级

6

有没有一种方法可以获取GridViewColumn的父级(ListView)?

我已经尝试使用LogicalTreeHelper和VisualTreeHelper,但都无法实现。

我可以分享一个有趣但丑陋的what-have-you-tried,它能够工作,但不能描述它的丑陋:

public class Prototype
{
    [Test, RequiresSTA]
    public void HackGetParent()
    {
        var lw = new ListView();
        var view = new GridView();
        var gvc = new GridViewColumn();
        view.Columns.Add(gvc);
        lw.View = view;
        var ancestor = new Ancestor<ListView>();

        var binding = new Binding
        {
            RelativeSource = new RelativeSource(RelativeSourceMode.FindAncestor, typeof(ListView), 1),
            Converter = new GetAncestorConverter<ListView>(), // Use converter to hack out the parent
            ConverterParameter = ancestor // conveterparameter used to return the parent
        };
        BindingOperations.SetBinding(gvc, GridViewColumn.WidthProperty, binding);

        lw.Items.Add(DateTime.Now); // think it cannot be empty for resolve to work
        ResolveBinding(lw);
        Assert.AreEqual(lw, ancestor.Instance);
    }

    private void ResolveBinding(FrameworkElement element)
    {
        element.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
        element.Arrange(new Rect(element.DesiredSize));
        element.UpdateLayout();
    }
}

public class GetAncestorConverter<T> : IValueConverter
{
    public object Convert(object value, Type type, object parameter, CultureInfo culture)
    {
        var ancestor = (Ancestor<T>)parameter;
        ancestor.Instance = (T)value;
        return null;
    }

    public object ConvertBack(object o, Type type, object parameter, CultureInfo culture)
    {
        throw new NotSupportedException();
    }
}

public class Ancestor<T>
{
    public T Instance { get; set; }
}
2个回答

6
很遗憾,您想要的内容被隐藏在DependencyObject的内部属性InheritanceContext后面,因此唯一访问它的方法是通过反射。如果您对此感到舒适,那么这个解决方案将起作用。
public class Prototype
{
    [Test, RequiresSTA]
    public void HackReflectionGetParent()
    {
        var lw = new ListView();
        var view = new GridView();
        var gvc = new GridViewColumn();
        view.Columns.Add(gvc);
        lw.View = view;

        var resolvedLw = gvc.GetParents().OfType<ListView>().FirstOrDefault();
        Assert.AreEqual(lw, resolvedLw);
    }
}

public static class DependencyObjectExtensions
{
    private static readonly PropertyInfo InheritanceContextProp = typeof (DependencyObject).GetProperty("InheritanceContext", BindingFlags.NonPublic | BindingFlags.Instance);

    public static IEnumerable<DependencyObject> GetParents(this DependencyObject child)
    {
        while (child != null)
        {
            var parent = LogicalTreeHelper.GetParent(child);
            if (parent == null)
            {
                if (child is FrameworkElement)
                {
                    parent = VisualTreeHelper.GetParent(child);
                }
                if (parent == null && child is ContentElement)
                {
                    parent = ContentOperations.GetParent((ContentElement) child);
                }
                if (parent == null)
                {
                    parent = InheritanceContextProp.GetValue(child, null) as DependencyObject;
                }
            }
            child = parent;
            yield return parent;
        }
    }
}

2009年曾有一些讨论,希望公开这个问题,但是至今为止没有任何进展,因此我认为不太可能会公开。但是,该属性在框架内被广泛使用,并且对其他框架程序集可见,因此我认为它不太可能很快改变。


不错的扩展方法,我觉得会很有用,谢谢您。 - Johan Larsson

0

我知道这个问题是3年前提出的,但我现在已经需要几次了,而且我总是遇到这个答案,所以我认为其他遇到这个问题的人也会有同样的问题。

我找到了一个简单的解决方案,可以解决这个问题和类似的问题,只要在实例化listview或gridview的父对象时添加一些代码即可。

长话短说:我利用.NET System.Collections.Generic.Dictionary功能创建这样一个字典("我被通知的对象类型", "我需要检索的对象类型"),例如Dictionary(Of GridViewColumn, ListView) - 并在父对象实例化时加载它。如果我得到一个GridViewColumn并且我需要知道它的“父”listview是什么,我只需参考这个字典就可以了。

对我来说似乎很好用 :)


1
样例代码通常在答案中很有用。但我现在还不够理解它,无法点赞。 - Johan Larsson

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接