I am attempting to display the results of a query in a WPF datagrid. The ItemsSource type I am binding to is IEnumerable<dynamic>
. As the fields returned are not determined until runtime I don't know the type of the data until the query is evaluated. Each "row" is returned as an ExpandoObject
with dynamic properties representing the fields.
It was my hope that AutoGenerateColumns
(like below) would be able to generate columns from an ExpandoObject
like it does with a static type but it does not appear to.
<DataGrid AutoGenerateColumns="True" ItemsSource="{Binding Results}"/>
Is there anyway to do this declaratively or do I have to hook in imperatively with some C#?
EDIT
Ok this will get me the correct columns:
// ExpandoObject implements IDictionary<string,object>
IEnumerable<IDictionary<string, object>> rows = dataGrid1.ItemsSource.OfType<IDictionary<string, object>>();
IEnumerable<string> columns = rows.SelectMany(d => d.Keys).Distinct(StringComparer.OrdinalIgnoreCase);
foreach (string s in columns)
dataGrid1.Columns.Add(new DataGridTextColumn { Header = s });
So now just need to figure out how to bind the columns to the IDictionary values.
Although there is an accepted answer by the OP, it uses
AutoGenerateColumns="False"
which is not exactly what the original question asked for. Fortunately, it can be solved with auto-generated columns as well. The key to the solution is theDynamicObject
that can have both static and dynamic properties:For the
ICustomTypeDescriptor
implementation, you can mostly use the static functions ofTypeDescriptor
in a trivial manner.GetProperties()
is the one that requires real implementation: reading the existing properties and adding your dynamic ones.As
PropertyDescriptor
is abstract, you have to inherit it:The problem here is that the clr will create columns for the ExpandoObject itself - but there is no guarantee that a group of ExpandoObjects share the same properties between each other, no rule for the engine to know which columns need to be created.
Perhaps something like Linq anonymous types would work better for you. I don't know what kind of a datagrid you are using, but binding should should be identical for all of them. Here is a simple example for the telerik datagrid.
link to telerik forums
This isn't actually truly dynamic, the types need to be known at compile time - but this is an easy way of setting something like this at runtime.
If you truly have no idea what kind of fields you will be displaying the problem gets a little more hairy. Possible solutions are:
MSDN on Reflection.Emit
An old but useful article on codeproject
Using Dynamic Linq
Getting around anonymous type headaches with dynamic linq
With dynamic linq you can create anonymous types using a string at runtime - which you can assemble from the results of your query. Example usage from the second link:
In any case, the basic idea is to somehow set the itemgrid to a collection of objects whose shared public properties can be found by reflection.
my answer from Dynamic column binding in Xaml
I've used an approach that follows the pattern of this pseudocode
DynamicTypeHelper.GetDynamicType() generates a type with simple properties. See this post for the details on how to generate such a type
Then to actually use the type, do something like this
Ultimately I needed to do two things:
After that the built-in data binding kicked in and worked fine and didn't seem to have any issue getting the property values out of the
ExpandoObject
.and