我可以使用反射访问ItemsControl的ItemsHost吗?

4

我正在创建一个自定义的ItemsControl,它是从DataGrid派生出来的。我需要访问DataGrid实际持有行的Panel,也就是ItemsHost。我见过一些丑陋的技巧来做到这一点,但我认为它们比使用反射更糟糕。

那么,我可以使用反射来访问ItemsHost吗?如何操作?


你是在讨论这个吗?https://dev59.com/jEfRa4cB1Zd3GeqP5gfB - Nate Noonen
不完全正确。请看下面我的回答。 - Rasto
2个回答

6

是的,我可以。这很简单-我刚刚在继承自DataGrid的类中创建了属性:

protected Panel ItemsHost {
    get {
        return (Panel) typeof (MultiSelector).InvokeMember("ItemsHost",
            BindingFlags.NonPublic | BindingFlags.GetProperty | BindingFlags.Instance,
            null, this, null);
    }
}

这个功能非常好用 :). 我可以获取ItemsControl类的ItemsHost内部属性的值。这样我就可以访问任何非受保护的属性。


我不知道这个是做什么的,也不知道为什么它能够工作,但是它确实可以在我的ItemsControl中正常运行 :) - dain
1
你可以使用 typeof(ItemsControl) 代替 typeof(MultiSelector),那样就适用于所有 ItemsControls - Corentin Pane

0

如果你喜欢@rasto的答案,但是你担心反射的性能问题,那么这个实现使用表达式树来创建一个强类型的Func<ItemsControl, Panel>。你只需要一次反射成本。你还可以将其封装在一个方便的扩展方法中...

public static class ItemsControlExtensions
{

    private static readonly Lazy<Func<ItemsControl, Panel?>> getItemsHost
        = new (CreateGetItemsHostLambda);
    
    private static Func<ItemsControl, Panel?> CreateGetItemsHostLambda()
    {
        var parameter = Expression.Parameter(type: typeof(ItemsControl));

        return Expression.Lambda<Func<ItemsControl, Panel>>(
            body: Expression.Property(
                expression: parameter, 
                property: typeof(ItemsControl).GetProperty(
                    name: "ItemsHost",
                    bindingAttr: BindingFlags.NonPublic 
                        | BindingFlags.GetProperty 
                        | BindingFlags.Instance
                )!
            ),
            parameter
        ).Compile();
    }
    
    public static Panel? GetItemsPanel(this ItemsControl itemsControl) 
        => getItemsHost.Value(itemsControl);

}

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