I have a grid, and I\'m setting the DataSource to a List. What I want is to have the list bind to the underlying type, and disply
Data-binding to lists follows the following strategy:
IListSource? if so, goto 2 with the result of GetList()IList? if not, throw an error; list expectedITypedList? if so use this for metadata (exit)public Foo this[int index] (for some Foo)? if so, use typeof(Foo) for metadatalist[0]) for metadataList<IListItem> falls into "4" above, since it has a typed indexer of type IListItem - and so it will get the metadata via TypeDescriptor.GetProperties(typeof(IListItem)).
So now, you have three options:
TypeDescriptionProvider that returns the properties for IListItem - I'm not sure this is feasible since you can't possibly know what the concrete type is given just IListItemList<User> etc) - simply as a simple way of getting an IList with a non-object indexerITypedList wrapper (lots of work)ArrayList (i.e. no public non-object indexer) - very hacky!My preference is for using the correct type of List<>... here's an AutoCast method that does this for you without having to know the types (with sample usage);
Note that this only works for homogeneous data (i.e. all the objects are the same), and it requires at least one object in the list to infer the type...
// infers the correct list type from the contents
static IList AutoCast(this IList list) {
if (list == null) throw new ArgumentNullException("list");
if (list.Count == 0) throw new InvalidOperationException(
"Cannot AutoCast an empty list");
Type type = list[0].GetType();
IList result = (IList) Activator.CreateInstance(typeof(List<>)
.MakeGenericType(type), list.Count);
foreach (object obj in list) result.Add(obj);
return result;
}
// usage
[STAThread]
static void Main() {
Application.EnableVisualStyles();
List<IListItem> data = new List<IListItem> {
new User { Id = "1", Name = "abc", UserSpecificField = "def"},
new User { Id = "2", Name = "ghi", UserSpecificField = "jkl"},
};
ShowData(data, "Before change - no UserSpecifiedField");
ShowData(data.AutoCast(), "After change - has UserSpecifiedField");
}
static void ShowData(object dataSource, string caption) {
Application.Run(new Form {
Text = caption,
Controls = {
new DataGridView {
Dock = DockStyle.Fill,
DataSource = dataSource,
AllowUserToAddRows = false,
AllowUserToDeleteRows = false
}
}
});
}