如何使用DataGridView显示字典? [英] How to display a Dictionary using DataGridView?

查看:208
本文介绍了如何使用DataGridView显示字典?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想使用 DataGridView 在Windows窗体中显示一个 Dictionary< string,TData> 。引用我的具体用例如下:字典键是列名,代表一个月,数据类型是十进制。

I want to display a Dictionary<string, TData> in Windows Forms using a DataGridView. The particular use case that lead me to that was the following: the dictionary key is the column name, representing a month, and the data type is decimal.

所以在那个情况下,对于每一列,我们有一个月和相应的十进制数。我希望DataGridView显示这几个月的列,并执行与字典条目的数据绑定。

So in that case, for each column we have a month and a corresponding decimal number. I wanted the DataGridView to display the columns for the months and perform a data binding to the entries of the dictionary.

显然这还有一个微不足道的解决方案:创建一个包含12个属性,每个类型为每个月的小数。创建一个DataGridView并执行一个传统的数据绑定到这个视图模型,数据源是一个这样的查看模型对象的列表。

Obviously this has another trivial solution: create a view model containing 12 properties, each of type decimal for each month. Create a DataGridView and perform a traditional data binding to this view model, with the data source being a list of such view model objects.

但这是一个乏味的事情。我们需要创建一些可以通过使用字典自动化的东西。

But this is tedious. We need to create a bunch of things that can be automated by using the dictionary.

我的问题是列需要根据字典和数据绑定必须以这种方式完成。

My problem is that the columns will need to be dynamically created based on the dictionary and the data binding will have to be done in that way.

我已经google了一下,找到了绑定类,它允许创建绑定。但是我不知道如何使用它将动态创建的列绑定到字典中的条目。

I googled a little on that and found the Binding class, which allows to create bindings. But I don't know how to use this to bind dynamically created columns to entries in a dictionary.

如何做?

推荐答案

您需要实现 ICustomTypeDescriptor 可在 DataGridView PropertyGrid

选项1 - 实现ICustomTypeDescriptor

您可以实现 ICustomTypeDescriptor 然后您可以编辑 DataGridView 中的字典。您可以通过一些小的更改使用实现。那么你可以这样简单地编辑字典:

You can implement ICustomTypeDescriptor and then you can edit the dictionary in DataGridView. You can use this implementation with some small changes. Then you can simply edit dictionary this way:

Dictionary<string, int> dictionary;
public void Form1_Load(object sender, EventArgs e)
{
    dictionary = new Dictionary<string, int>() { { "A", 1 }, { "B", 2 }, { "C", 3 } };
    dataGridView1.DataSource =  new BindingSource(new DictionaryAdapter(dictionary) , "");
}

或者如果您愿意,可以将其设置为 PropertyGrid 中的SelectedObject

Or if you prefer, you can set it as SelectedObject of a PropertyGrid:

propertyGrid1.SelectedObject =  new DictionaryAdapter(dictionary);

这是实现:

public class DictionaryAdapter : ICustomTypeDescriptor
{
    IDictionary dictionary;
    public DictionaryAdapter(IDictionary d)
    {
        dictionary = d;
    }
    public string GetComponentName()
    {
        return TypeDescriptor.GetComponentName(this, true);
    }
    public EventDescriptor GetDefaultEvent()
    {
        return TypeDescriptor.GetDefaultEvent(this, true);
    }
    public string GetClassName()
    {
        return TypeDescriptor.GetClassName(this, true);
    }
    public EventDescriptorCollection GetEvents(Attribute[] attributes)
    {
        return TypeDescriptor.GetEvents(this, attributes, true);
    }
    EventDescriptorCollection System.ComponentModel.ICustomTypeDescriptor.GetEvents()
    {
        return TypeDescriptor.GetEvents(this, true);
    }
    public TypeConverter GetConverter()
    {
        return TypeDescriptor.GetConverter(this, true);
    }

    public object GetPropertyOwner(PropertyDescriptor pd)
    {
        return dictionary;
    }
    public AttributeCollection GetAttributes()
    {
        return TypeDescriptor.GetAttributes(this, true);
    }
    public object GetEditor(Type editorBaseType)
    {
        return TypeDescriptor.GetEditor(this, editorBaseType, true);
    }
    public PropertyDescriptor GetDefaultProperty()
    {
        return null;
    }
    PropertyDescriptorCollection 
        System.ComponentModel.ICustomTypeDescriptor.GetProperties()
    {
        return ((ICustomTypeDescriptor)this).GetProperties(new Attribute[] { });
    }
    public PropertyDescriptorCollection GetProperties(Attribute[] attributes)
    {
        ArrayList properties = new ArrayList();
        foreach (DictionaryEntry e in dictionary)
        {
            properties.Add(new DictionaryPropertyDescriptor(dictionary, 
                e.Key.ToString()));
        }
        PropertyDescriptor[] props = 
            (PropertyDescriptor[])properties.ToArray(typeof(PropertyDescriptor));
        return new PropertyDescriptorCollection(props);
    }
}
public class DictionaryPropertyDescriptor : PropertyDescriptor
{
    IDictionary dictionary;
    string key;

    internal DictionaryPropertyDescriptor(IDictionary d, string k)
        : base(k.ToString(), null)
    {
        dictionary = d;
        key = k;
    }
    public override Type PropertyType
    {
        get { return dictionary[key].GetType(); }
    }
    public override void SetValue(object component, object value)
    {
        dictionary[key] = value;
    }
    public override object GetValue(object component)
    {
        return dictionary[key];
    }
    public override bool IsReadOnly
    {
        get { return false; }
    }
    public override Type ComponentType
    {
        get { return null; }
    }
    public override bool CanResetValue(object component)
    {
        return false;
    }
    public override void ResetValue(object component)
    {
    }
    public override bool ShouldSerializeValue(object component)
    {
        return false;
    }
}

选项2 - 使用DataTable

Option 2 - Use a DataTable

另外作为一个简单的选项,您可以将 Dictionary 设置为 DataTable 并编辑数据。

Also as a simple option you can shape the Dictionary to a DataTable and edit data.

您可以为此任务创建扩展方法:

You can create extension methods for this task:

public static class DictionaryExtensions
{
    public static DataTable ToDataTable<T>(this Dictionary<string, T> dictionary)
    {
        var dt = new DataTable();
        dictionary.Keys.ToList().ForEach(x => dt.Columns.Add(x, typeof(T)));
        dt.Rows.Add(dictionary.Values.Cast<object>().ToArray());
        return dt;
    }
    public static void UpdateFromDataTable<T>(this Dictionary<string, T> dictionary, 
        DataTable table)
    {
        if (table.Rows.Count == 1)
            table.Columns.Cast<DataColumn>().ToList().ForEach(x => 
                dictionary[x.ColumnName] = table.Rows[0].Field<T>(x.ColumnName));
    }
}

这样使用这些扩展方法:

And use these extension methods this way:

Dictionary<string, int> dictionary;
public void Form1_Load(object sender, EventArgs e)
{
    dictionary = new Dictionary<string, int>() { { "A", 1 }, { "B", 2 }, { "C", 3 } };
    dataGridView1.DataSource = dictionary.ToDataTable();
}
private void button1_Click(object sender, EventArgs e)
{
    dictionary.UpdateFromDataTable(dataGridView1.DataSource as DataTable);
}

这篇关于如何使用DataGridView显示字典?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆