我有一个DataGrid
我设置ItemsSource
是 ObservableCollection<Dictionary<String, object>>
对象。
通常,我只是定义一个 ClassA
并设置ObservableCollection<ClassA>
到 ItemsSource,然后我可以将属性名称绑定(bind)到 ClassA 的列( DataGridTextColumn
)。
但我不知道如何绑定(bind)字典的键/值。
有支持吗?
最佳答案
你要问的是相当复杂的,为了创建 ObservableDictionary<TKey, TValue>
应该创建一个类来实现:
IDictionary
INotifyCollectionChanged
INotifyPropertyChanged
ICollection<KeyValuePair<TKey,TValue>>
IEnumerable<KeyValuePair<TKey,TValue>>
IEnumerable
接口(interface)。 More in depth在这里。这种实现的一个例子是:
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
}
}
替代方案是这个nice solution一个可绑定(bind)的动态字典,将每个字典条目公开为一个属性。
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" />
自动生成列事件:
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) });
}
}
关于c# - 在 WPF 中使用 ObservableCollection<Dictionary<String, Object>> 作为 DataGrid Itemsource,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44665733/