There's no clean way to do this in WinForms. You have a couple of options, ranging from easiest to hardest:
LINQ
(Specifically here anonymous types).
You can do something like this:
dataGridView.DataSource = from x in dataSource
select new
{
Property = x.Property,
SubProperty = x.ObjectProperty.SubProperty // etc.
};
This is by far the simplest approach, but it's also one-way binding; you cannot update data using this mechanism. This will also give you no design-time support for the grid, as the property names can't be discovered at design time.
Wrapper Class
This, I'm assuming, you're familiar with. You create a class that wraps your actual data-bound class, passing through the properties and bringing up the "sub-properties" to the class level. For example:
public string SubProperty
{
get { return yourObject.ObjectProperty.SubProperty; }
set { yourObject.ObjectProperty.SubProperty = value; }
}
This will give you design-time support for the grid (assuming that you use a BindingSource
component and properly set up an object data source for this object) and will allow for two-way binding. It does, however, require that you roll a wrapper class and create every property that you want to bind to.
Custom Type Descriptor
This is the most difficult, but it's also the most flexible, fastest, and cleanest (from an external API perspective). I won't go into the ins and outs of how to do this in this post, but there are articles available on this. I would link to the MSDN page on custom TypeDescriptors, but it's a little daunting and extends beyond the scope of what you're trying to do.
In short, you create a custom TypeDescriptor class that provides a list of PropertyDescriptor instances. These allow you complete control over the binding experience, rather than relying on reflection (as would be the case in either of the above two cases). This is a non-trivial amount of code, though, so you'll need to decide if this is what you really want to do before you set out to do it.
This is a pretty good introduction to the TypeDescriptor
class and what it does. What you're interested here is the PropertyDescriptorCollection
. You just need to return a PropertyDescriptor
for every property you want to interact with, including nested properties.