Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/wpf/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/r/75.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 将DataGrid绑定到ObservableCollection<;字典>;_C#_Wpf_Data Binding_Dictionary - Fatal编程技术网

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) });
  }
}