我正在创建一个自定义的ItemsControl
,它是从DataGrid
派生出来的。我需要访问DataGrid
实际持有行的Panel
,也就是ItemsHost
。我见过一些丑陋的技巧来做到这一点,但我认为它们比使用反射更糟糕。
那么,我可以使用反射来访问ItemsHost
吗?如何操作?
我正在创建一个自定义的ItemsControl
,它是从DataGrid
派生出来的。我需要访问DataGrid
实际持有行的Panel
,也就是ItemsHost
。我见过一些丑陋的技巧来做到这一点,但我认为它们比使用反射更糟糕。
那么,我可以使用反射来访问ItemsHost
吗?如何操作?
是的,我可以。这很简单-我刚刚在继承自DataGrid
的类中创建了属性:
protected Panel ItemsHost {
get {
return (Panel) typeof (MultiSelector).InvokeMember("ItemsHost",
BindingFlags.NonPublic | BindingFlags.GetProperty | BindingFlags.Instance,
null, this, null);
}
}
这个功能非常好用 :). 我可以获取ItemsControl
类的ItemsHost
内部属性的值。这样我就可以访问任何非受保护的属性。
typeof(ItemsControl)
代替 typeof(MultiSelector)
,那样就适用于所有 ItemsControls
。 - Corentin Pane如果你喜欢@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);
}