4

I'm creating custom ItemsControl that is derived from DataGrid. I need to access ItemsHost that is the Panel that actually holds rows of DataGrid. I have seen som ugly tricks to do that but I consider them worse then using reflection. So can I access ItemsHost using reflection ? And how ?

Rasto
  • 17,204
  • 47
  • 154
  • 245

2 Answers2

6

Yes I can. It is simple - I've just created property in class inheriting from DataGrid:

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

It works like a charm :). I can get the value of ItemsHost internal property of the ItemsControl class. This way I can access any non-protected properties.

Rasto
  • 17,204
  • 47
  • 154
  • 245
  • I have no idea what this does or why this works, but for sure it does work with my ItemsControl :) – dain Jan 26 '12 at 15:27
  • 1
    You could use `typeof(ItemsControl)` instead of `typeof(MultiSelector)`, that would work for all `ItemsControls` then. – Corentin Pane Mar 09 '21 at 10:38
0

If you're a fan of @rasto's answer, but you're concerned about the performance of reflection, this implementation uses expression trees to create a strongly typed Func<ItemsControl, Panel>. You incur the reflection cost only once. You can also wrap it up in a handy extension method...

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);

}
Mike Christiansen
  • 1,104
  • 2
  • 13
  • 30