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 IListItem
List<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
}
}
});
}