将DataGrid绑定到ObservableCollection

我有一个ObservableCollection并希望将它绑定到DataGrid

 ObservableDictionary NewRecord1 = new ObservableDictionary(); Dictionary Record1 = new Dictionary(); Record1.Add("FirstName", "FName1"); Record1.Add("LastName", "LName1"); Record1.Add("Age", "32"); DictRecords.Add(Record1); Dictionary Record2 = new Dictionary(); NewRecord2.Add("FirstName", "FName2"); NewRecord2.Add("LastName", "LName2"); NewRecord2.Add("Age", "42"); DictRecords.Add(Record2); 

我希望键成为DataGrid的标题,并将每个Dictionary项的值作为行。 设置ItemsSource不起作用。

您可以使用可绑定的动态字典。 这会将每个字典条目公开为属性。

 ///  /// Bindable dynamic dictionary. ///  public sealed class BindableDynamicDictionary : DynamicObject, INotifyPropertyChanged { ///  /// The internal dictionary. ///  private readonly Dictionary _dictionary; ///  /// Creates a new BindableDynamicDictionary with an empty internal dictionary. ///  public BindableDynamicDictionary() { _dictionary = new Dictionary(); } ///  /// Copies the contents of the given dictionary to initilize the internal dictionary. ///  ///  public BindableDynamicDictionary(IDictionary source) { _dictionary = new Dictionary(source); } ///  /// You can still use this as a dictionary. ///  ///  ///  public object this[string key] { get { return _dictionary[key]; } set { _dictionary[key] = value; RaisePropertyChanged(key); } } ///  /// This allows you to get properties dynamically. ///  ///  ///  ///  public override bool TryGetMember(GetMemberBinder binder, out object result) { return _dictionary.TryGetValue(binder.Name, out result); } ///  /// This allows you to set properties dynamically. ///  ///  ///  ///  public override bool TrySetMember(SetMemberBinder binder, object value) { _dictionary[binder.Name] = value; RaisePropertyChanged(binder.Name); return true; } ///  /// This is used to list the current dynamic members. ///  ///  public override IEnumerable GetDynamicMemberNames() { return _dictionary.Keys; } public event PropertyChangedEventHandler PropertyChanged; private void RaisePropertyChanged(string propertyName) { var propChange = PropertyChanged; if (propChange == null) return; propChange(this, new PropertyChangedEventArgs(propertyName)); } } 

然后你可以像这样使用它:

  private void testButton1_Click(object sender, RoutedEventArgs e) { // Creating a dynamic dictionary. var dd = new BindableDynamicDictionary(); //access like any dictionary dd["Age"] = 32; //or as a dynamic dynamic person = dd; // Adding new dynamic properties. // The TrySetMember method is called. person.FirstName = "Alan"; person.LastName = "Evans"; //hacky for short example, should have a view model and use datacontext var collection = new ObservableCollection(); collection.Add(person); dataGrid1.ItemsSource = collection; } 

Datagrid需要自定义代码来构建列:

XAML:

  

AutoGeneratedColumns事件:

  private void dataGrid1_AutoGeneratedColumns(object sender, EventArgs e) { var dg = sender as DataGrid; var first = dg.ItemsSource.Cast().FirstOrDefault() as DynamicObject; if (first == null) return; var names = first.GetDynamicMemberNames(); foreach(var name in names) { dg.Columns.Add(new DataGridTextColumn { Header = name, Binding = new Binding(name) }); } } 

基于westons回答我提出了另一种解决方案,而没有使用自定义的BindableDynamicDictionary类。

在名称空间System.Dynamic (在ASP.NET中大量使用)中有一个名为ExpandoObject的类。

它基本上与westons BindableDynamicDictionary做同样的事情,缺点是没有索引操作符,因为它显式实现了接口IDictionary

 private void MyDataGrid_AutoGeneratedColumns(object sender, EventArgs e) { var dg = sender as DataGrid; dg.Columns.Clear(); var first = dg.ItemsSource.Cast().FirstOrDefault() as IDictionary; if (first == null) return; var names = first.Keys; foreach (var name in names) { dg.Columns.Add(new DataGridTextColumn { Header = name, Binding = new Binding(name) }); } } 

请注意,这里唯一的区别是您必须将ExpandoObjectIDictionary以通过索引运算符访问/添加值或属性。