开发者

Shape of items in WPF DataGrid ItemsSource when AutoGenerateColumns = False

When I am using a WPF DataGrid (I assume the SL version works similarly), and I specify the columns at run time (i.e. they aren’t known at compile time, so auto-generating columns via Reflection doesn’t work)

How can I provide items so that they show up properly in the grid? In other words, given the following DataGrid:

<DataGrid x:Name="dataGrid" AutoGenerateColumns="False">
  <DataGrid.Columns>
    <DataGridTextColumn Header="Foo"/>
    <DataGridTextColumn Header="Bar"/>
    <DataGridTextColumn Header="Baz"/>
  </DataGrid.Columns>
</DataGrid>

I’ve tried th开发者_运维知识库e following:

dataGrid.Items.Add(new[] {"a1", "a2", "a3"});
dataGrid.Items.Add(new[] {"b1", "b2", "b3"});

and

dataGrid.Items.Add(new Dictionary<string, string>() {
    {"Foo", "a1"},
    {"Bar", "a2"},
    {"Baz", "a3"},
});

dataGrid.Items.Add(new Dictionary<string, string>() {
    {"Foo", "b1"},
    {"Bar", "b2"},
    {"Baz", "b3"},
});

Note that even though in my example the columns are defined in Xaml and are static, for my app, they will not be in Xaml and will be generated at Runtime (so I can't just create a class with properties "Foo", "Bar", "Baz")


Your best bet is probably to present your items in the form of a class that implements ICustomTypeDescriptor. That way, you can dynamically add properties as needed, and the DataGrid will pick them up automatically (if you set AutoGenerateColumns back to true).

Another option would be to use an ExpandoObject, but the DataGrid won't be able to detect the properties automatically. However it works if you create the columns manually:

dg.Columns.Add(new DataGridTextColumn { Header = "Foo", Binding = new Binding("Foo") });
dg.Columns.Add(new DataGridTextColumn { Header = "Bar", Binding = new Binding("Bar") });
dg.Columns.Add(new DataGridTextColumn { Header = "Baz", Binding = new Binding("Baz") });


dynamic x = new ExpandoObject();
x.Foo = 42;
x.Bar = "Hello";
x.Baz = DateTime.Today;
dg.Items.Add(x);

x = new ExpandoObject();
x.Foo = 0;
x.Bar = "zzz";
x.Baz = DateTime.MinValue;
dg.Items.Add(x);

EDIT: actually, I realize you probably won't know the names of the properties at compile time, so ExpandoObject won't work for you. Instead you can use the example class I posted in this blog post, and add methods to access the properties by name:

public class MyDynamicObject : DynamicObject
{
    private Dictionary<string, object> _properties = new Dictionary<string, object>();

    public override bool TryGetMember(GetMemberBinder binder, out object result)
    {
        return _properties.TryGetValue(binder.Name, out result);
    }

    public override bool TrySetMember(SetMemberBinder binder, object value)
    {
        _properties[binder.Name] = value;
        return true;
    }

    public void SetProperty(string name, object value)
    {
        _properties[name] = value;
    }

    public object GetProperty(string name)
    {
        return _properties[name];
    }
}

EDIT2: I just realize I forgot another very simple approach: use a DataTable. It's easy to setup, and the DataGrid will be able to generate the columns automatically.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜