views:

574

answers:

2

I'm binding IList to a GridView. IMyInterface looks like

public interface IMyInterface: IHasTotalHours, IHasLines
{
    DateTime GoalStartDate { get; set; }
    DateTime GoalEndDate { get; set; }
}

I bind an instance to a Grid like this:

IList<IMyInterface> instance= GetMyData();

myGrid.DataSource = instance;
myGrid.DataBind();

When bind this to the grid, the only members that show up in the grid are the direct members of IMyInterface: GoalStartDate and GoalEndDate.

Why is that? How do I get the grid to display the members of the other interfaces it inherits?

Update The inherited interfaces define simple data properties like

public interface IHasTotalHours
{
    string Description { get; set; }
    int Hours{ get; set; }
}
public interface IHasLines
{
    double TotalLines { get; set; }
    double LinesPerHour { get; set; }
}

There is a class that implements IMyInterface:

public class MyClass : IMyInterface
{
    public string Description { get; set; }
    public int Hours { get; set; }
    public double TotalLines { get; set; }
    public double LinesPerHour { get; set; }
    public DateTime GoalStartDate { get; set; }
    public DateTime GoalEndDate { get; set; }

}

These are cast as IMyInterface, and returned in the list that I'm binding to the GridView.

A: 

It's because an interface is a contract, and that's the only way to interact with an object is through that specific contract. The other interfaces cannot be assumed and can't be utilized until a cast is made.

So when you bind a List of T to something, the datagrid doesn't know about those other interfaces. And the datagrid isn't going to use reflection to figure out what other classes or interfaces might be inherited. The only object properties that are going to be available to the datagrid are the properties exposed by the T interface.

You need to bind List if you want the datagrid to have access to all the properties.

Chris Holmes
But if any class implementing IMyInterface has to implement the members of the other interfaces also, I don't get why those members aren't also visible. Not disagreeing with you. In the IDE when I hover over the instance, it only shows me the immediate members. I have to dig further to see the rest.
jlembke
So you are saying that instance should be List<IMyInterface>, not IList? I will give that a shot in the morning.
jlembke
Doesn't make a difference whether it's a List or IList. It's the TYPE that matters. The IMyInterface type exposes ONLY two properties. The datagrid can't possibly know about the others because its being given an IMyInterface type.
Chris Holmes
This answer does not really explain anything. When type B inherits from type A, then type B must satisfy the contract of type A. That's a basic requirement of polymorphism. Inherited members are part of the contract.
Wim Coenen
You might want to read up on the difference between an interface and a base class wcoenen. What you're talking about is correct for class inheritance. It is not true, however, for interfaces. A class does not "inherit" an interface. It implements it. There's a significant difference.
Chris Holmes
The difference is not significant for contracts. If "B is-a A", then B needs to satisfy the contract of A. Whether the "is-a" means "inherits from" or "implements interface" doesn't matter.
Wim Coenen
+3  A: 

Data bound controls do not use reflection but a TypeDescriptor to get the properties from a data source. In the TypeDescriptor.GetProperties method, you can read the following:

The properties for a component can differ from the properties of a class, because the site can add or remove properties if the component is sited.

Apparently the default implementation will only return direct properties from an Interface and not the inherited ones.

Luckily this mechanism is extensible, and you can write a TypeConverter class with custom property information implementation. Please refer to the remarks in the TypeConverter documentation for implementing property logic.

The GetProperties implementation of your custom TypeConverter class can call TypeDescriptor.GetProperties(Type) on your interface and all it's inherited interfaces. But maybe you could even write a generic TypeConverter that would find all inherited properties by using reflection.

Then you attach this custom TypeConverter to your interface with the TypeConverterAttribute attribute.

And then, like magic, the data source will find all properties. ;-)

bgever
Excellent. That is very helpful. Thanks a lot!
jlembke
For completeness, TypeConverter applies mainly to things like PropertyGrid; for grids, it is more common to use ITypesList or TypeDescriptionProvider - or sometimes (less common) ICustomTypeDescriptor (on the 0th item) - but rarely TypeConverter.
Marc Gravell