C# 将DataGrid绑定到ObservableCollection<;字典>;
我有一个C# 将DataGrid绑定到ObservableCollection<;字典>;,c#,wpf,data-binding,dictionary,C#,Wpf,Data Binding,Dictionary,我有一个ObservableCollection,想把它绑定到一个DataGrid ObservableDictionary<String,Object> NewRecord1 = new ObservableDictionary<string,object>(); Dictionary<String,Object> Record1 = new Dictionary<string,object>(); Record1.Add("FirstName
ObservableCollection
,想把它绑定到一个DataGrid
ObservableDictionary<String,Object> NewRecord1 = new ObservableDictionary<string,object>();
Dictionary<String,Object> Record1 = new Dictionary<string,object>();
Record1.Add("FirstName", "FName1");
Record1.Add("LastName", "LName1");
Record1.Add("Age", "32");
DictRecords.Add(Record1);
Dictionary<String, Object> Record2 = new Dictionary<string, object>();
NewRecord2.Add("FirstName", "FName2");
NewRecord2.Add("LastName", "LName2");
NewRecord2.Add("Age", "42");
DictRecords.Add(Record2);
observedictionary NewRecord1=newobservedictionary();
字典记录1=新字典();
记录1.添加(“名字”、“FName1”);
记录1.添加(“姓氏”、“LName1”);
记录1.添加(“年龄”、“32”);
记录。添加(记录1);
字典记录2=新字典();
新增记录2。添加(“名字”、“FName2”);
新增记录2。添加(“姓氏”、“LName2”);
新记录2.添加(“年龄”、“42”);
记录。添加(记录2);
我希望键成为
DataGrid
的标题,每个Dictionary
项的值成为行。设置itemsource
无效 您可以使用可绑定的动态字典。这将把每个字典条目作为属性公开
/// <summary>
/// Bindable dynamic dictionary.
/// </summary>
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>
/// <param name="source"></param>
public BindableDynamicDictionary(IDictionary<string, object> source)
{
_dictionary = new Dictionary<string, object>(source);
}
/// <summary>
/// You can still use this as a dictionary.
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
public object this[string key]
{
get
{
return _dictionary[key];
}
set
{
_dictionary[key] = value;
RaisePropertyChanged(key);
}
}
/// <summary>
/// This allows you to get properties dynamically.
/// </summary>
/// <param name="binder"></param>
/// <param name="result"></param>
/// <returns></returns>
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>
/// <param name="binder"></param>
/// <param name="value"></param>
/// <returns></returns>
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>
/// <returns></returns>
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));
}
}
//
///可绑定动态字典。
///
公共密封类BindableDynamicDictionary:DynamicObject,INotifyPropertyChanged
{
///
///内部字典。
///
私人只读词典;
///
///使用空的内部字典创建新的BindableDynamicDictionary。
///
公共BindableDynamicDictionary()
{
_字典=新字典();
}
///
///复制给定词典的内容以初始化内部词典。
///
///
公共BindableDynamicDictionary(IDictionary源)
{
_字典=新字典(来源);
}
///
///你仍然可以把它用作字典。
///
///
///
公共对象此[字符串键]
{
得到
{
返回字典[键];
}
设置
{
_字典[键]=值;
RaisePropertyChanged(键);
}
}
///
///这允许您动态获取属性。
///
///
///
///
公共重写bool TryGetMember(GetMemberBinder绑定器,输出对象结果)
{
返回_dictionary.TryGetValue(binder.Name,out结果);
}
///
///这允许您动态设置属性。
///
///
///
///
public override bool TrySetMember(SetMemberBinder绑定器,对象值)
{
_字典[binder.Name]=值;
RaisePropertyChanged(活页夹名称);
返回true;
}
///
///用于列出当前动态成员。
///
///
公共重写IEnumerable GetDynamicMemberNames()
{
返回_dictionary.Keys;
}
公共事件属性更改事件处理程序属性更改;
私有void RaisePropertyChanged(字符串propertyName)
{
var propChange=PROPERTYCHANGE;
if(propChange==null)返回;
propChange(这是新的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<object>();
collection.Add(person);
dataGrid1.ItemsSource = collection;
}
private void testButton1\u单击(对象发送者,路由目标)
{
//创建动态字典。
var dd=新的BindableDynamicDictionary();
//像任何字典一样访问
dd[“年龄”]=32;
//或者作为一种动力
动态人=dd;
//添加新的动态属性。
//调用TrySetMember方法。
person.FirstName=“艾伦”;
person.LastName=“Evans”;
//例如,hacky应该有一个视图模型并使用datacontext
var collection=新的ObservableCollection();
收集。添加(人);
dataGrid1.ItemsSource=集合;
}
Datagrid需要自定义代码来构建列:
XAML:
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) });
}
}
private void dataGrid1\u自动生成列(对象发送方,事件参数e)
{
var dg=发送方作为数据网格;
var first=dg.ItemsSource.Cast().FirstOrDefault()作为DynamicObject;
if(first==null)返回;
var name=first.GetDynamicMemberNames();
foreach(名称中的变量名称)
{
Add(newdatagridtextcolumn{Header=name,Binding=newbinding(name)});
}
}
基于westons的回答,我提出了另一个解决方案,没有使用自定义的BindableDynamicDictionary类
在命名空间System.Dynamic
(在ASP.NET中大量使用)中有一个名为ExpandoObject
的类
它与westons BindableDynamicDictionary基本相同,缺点是没有可用的索引运算符,因为它显式实现了接口IDictionary
private void MyDataGrid_自动生成列(对象发送方,事件参数e)
{
var dg=发送方作为数据网格;
dg.Columns.Clear();
var first=dg.ItemsSource.Cast().FirstOrDefault()作为IDictionary;
if(first==null)返回;
var name=first.Keys;
foreach(名称中的变量名称)
{
Add(newdatagridtextcolumn{Header=name,Binding=newbinding(name)});
}
}
请注意,这里唯一的区别是您必须将
ExpandoObject
强制转换为IDictionary
,才能通过索引操作符访问/添加值或属性。DataGrid根本不支持这一点。如果您需要动态列,还有其他方法。@HenkHolterman我确实需要动态列。你能告诉我其他的方法吗?在你的例子中,看起来你正在向网格中添加人员。我假设您需要动态列,因为您需要在其他时间在同一网格中显示除人员以外的其他内容?如果是这样,是否可以为需要显示的所有其他项目创建一个Person
类和类似类(而不是使用字典
)?@Sphinxxx是的。实际上是测试结果——多个测试按顺序运行,当前运行的测试结果将显示在数据网格中。我考虑为每个测试结果添加一个结果类。我是
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) });
}
}
private void MyDataGrid_AutoGeneratedColumns(object sender, EventArgs e)
{
var dg = sender as DataGrid;
dg.Columns.Clear();
var first = dg.ItemsSource.Cast<object>().FirstOrDefault() as IDictionary<string, object>;
if (first == null) return;
var names = first.Keys;
foreach (var name in names)
{
dg.Columns.Add(new DataGridTextColumn { Header = name, Binding = new Binding(name) });
}
}