在WPF中使用ObservableCollection >作为DataGrid Itemsource(Using ObservableCollection> as DataGrid Ite

编程入门 行业动态 更新时间:2024-10-27 14:28:09
在WPF中使用ObservableCollection >作为DataGrid Itemsource(Using ObservableCollection> as DataGrid Itemsource in WPF)

我有一个DataGrid ,我设置ItemsSource是一个ObservableCollection<Dictionary<String, object>>对象。

通常,我只是定义一个ClassA并将ObservableCollection<ClassA>设置为ItemsSource,然后我可以将属性名称绑定到ClassA的列( DataGridTextColumn )。

但我不知道如何绑定Dictionary的键/值。

有任何支持吗?

I have a DataGrid and I set ItemsSource is a ObservableCollection<Dictionary<String, object>> object.

Usually, I just define a ClassA and set ObservableCollection<ClassA> to ItemsSource, then I can binding properties name to columns(DataGridTextColumn) of ClassA.

But I don't know how to binding a key/value of a Dictionary.

Have any support?

最满意答案

你要问的是相当复杂的,为了创建ObservableDictionary<TKey, TValue>应该创建一个实现的类:

IDictionary INotifyCollectionChanged INotifyPropertyChanged ICollection<KeyValuePair<TKey,TValue>> IEnumerable<KeyValuePair<TKey,TValue>> IEnumerable

接口。 在这里更深入 。 这种实施的一个例子是:

class ObservableDictionary<TKey, TValue> : IDictionary, INotifyCollectionChanged, INotifyPropertyChanged { private Dictionary<TKey, TValue> mDictionary; //Methods & Properties for IDictionary implementation would defer to mDictionary: public void Add(TKey key, TValue value) { mDictionary.Add(key, value); OnCollectionChanged(NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, value) return; } //Implementation of INotifyCollectionChanged: public event NotifyCollectionChangedEventHandler CollectionChanged; protected void OnCollectionChanged(NotifyCollectionChangedEventArgs args) { //event fire implementation } //Implementation of INotifyProperyChanged: public event ProperyChangedEventHandler ProperyChanged; protected void OnPropertyChanged(PropertyChangedEventArgs args) { //event fire implementation } }

另一种是可绑定动态字典的优秀解决方案 ,它将每个字典条目公开为属性。

public sealed class BindableDynamicDictionary : DynamicObject, INotifyPropertyChanged { /// <summary> /// The internal dictionary. /// </summary> private readonly Dictionary<string, object> _dictionary; /// <summary> /// Creates a new BindableDynamicDictionary with an empty internal dictionary. /// </summary> public BindableDynamicDictionary() { _dictionary = new Dictionary<string, object>(); } /// <summary> /// Copies the contents of the given dictionary to initilize the internal dictionary. /// </summary> public BindableDynamicDictionary(IDictionary<string, object> source) { _dictionary = new Dictionary<string, object>(source); } /// <summary> /// You can still use this as a dictionary. /// </summary> public object this[string key] { get { return _dictionary[key]; } set { _dictionary[key] = value; RaisePropertyChanged(key); } } /// <summary> /// This allows you to get properties dynamically. /// </summary> public override bool TryGetMember(GetMemberBinder binder, out object result) { return _dictionary.TryGetValue(binder.Name, out result); } /// <summary> /// This allows you to set properties dynamically. /// </summary> public override bool TrySetMember(SetMemberBinder binder, object value) { _dictionary[binder.Name] = value; RaisePropertyChanged(binder.Name); return true; } /// <summary> /// This is used to list the current dynamic members. /// </summary> public override IEnumerable<string> 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) { var dd = new BindableDynamicDictionary(); // Creating a dynamic dictionary. dd["Age"] = 32; //access like any dictionary dynamic person = dd; //or as a dynamic person.FirstName = "Alan"; // Adding new dynamic properties. The TrySetMember method is called. person.LastName = "Evans"; //hacky for short example, should have a view model and use datacontext var collection = new ObservableCollection<object>(); collection.Add(person); dataGrid1.ItemsSource = collection; }

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

XAML:

<DataGrid AutoGenerateColumns="True" Name="dataGrid1" AutoGeneratedColumns="dataGrid1_AutoGeneratedColumns" />

AutoGeneratedColumns事件:

private void dataGrid1_AutoGeneratedColumns(object sender, EventArgs e) { var dg = sender as DataGrid; var first = dg.ItemsSource.Cast<object>().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) }); } }

What youre asking is rather complex, in order to create ObservableDictionary<TKey, TValue> one should create a class that implements:

IDictionary INotifyCollectionChanged INotifyPropertyChanged ICollection<KeyValuePair<TKey,TValue>> IEnumerable<KeyValuePair<TKey,TValue>> IEnumerable

interfaces. More in depth in here. An example of such implemntion is:

class ObservableDictionary<TKey, TValue> : IDictionary, INotifyCollectionChanged, INotifyPropertyChanged { private Dictionary<TKey, TValue> mDictionary; //Methods & Properties for IDictionary implementation would defer to mDictionary: public void Add(TKey key, TValue value) { mDictionary.Add(key, value); OnCollectionChanged(NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, value) return; } //Implementation of INotifyCollectionChanged: public event NotifyCollectionChangedEventHandler CollectionChanged; protected void OnCollectionChanged(NotifyCollectionChangedEventArgs args) { //event fire implementation } //Implementation of INotifyProperyChanged: public event ProperyChangedEventHandler ProperyChanged; protected void OnPropertyChanged(PropertyChangedEventArgs args) { //event fire implementation } }

An alterntive is this nice solution of a bindable dynamic dictionary, that expose each dictionary entry as a property.

public sealed class BindableDynamicDictionary : DynamicObject, INotifyPropertyChanged { /// <summary> /// The internal dictionary. /// </summary> private readonly Dictionary<string, object> _dictionary; /// <summary> /// Creates a new BindableDynamicDictionary with an empty internal dictionary. /// </summary> public BindableDynamicDictionary() { _dictionary = new Dictionary<string, object>(); } /// <summary> /// Copies the contents of the given dictionary to initilize the internal dictionary. /// </summary> public BindableDynamicDictionary(IDictionary<string, object> source) { _dictionary = new Dictionary<string, object>(source); } /// <summary> /// You can still use this as a dictionary. /// </summary> public object this[string key] { get { return _dictionary[key]; } set { _dictionary[key] = value; RaisePropertyChanged(key); } } /// <summary> /// This allows you to get properties dynamically. /// </summary> public override bool TryGetMember(GetMemberBinder binder, out object result) { return _dictionary.TryGetValue(binder.Name, out result); } /// <summary> /// This allows you to set properties dynamically. /// </summary> public override bool TrySetMember(SetMemberBinder binder, object value) { _dictionary[binder.Name] = value; RaisePropertyChanged(binder.Name); return true; } /// <summary> /// This is used to list the current dynamic members. /// </summary> public override IEnumerable<string> 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)); } }

Then you can use it like this:

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

Datagrid needs custom code for building the columns up:

XAML:

<DataGrid AutoGenerateColumns="True" Name="dataGrid1" AutoGeneratedColumns="dataGrid1_AutoGeneratedColumns" />

AutoGeneratedColumns event:

private void dataGrid1_AutoGeneratedColumns(object sender, EventArgs e) { var dg = sender as DataGrid; var first = dg.ItemsSource.Cast<object>().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) }); } }

更多推荐

本文发布于:2023-07-20 20:40:00,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1203713.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:ObservableCollection   WPF   Itemsource   DataGrid

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!