DataGridView绑定到包含字典

时间:2017-03-08 12:38:14

标签: c# .net winforms datagridview datasource

我成功绑定到对象列表并将其设置为DataGridViews数据源。在运行时定义列,其中包括相应的DataPropertyNames。

但是我现在需要在我的对象类中添加一个列表。此列表的大小是动态的,但对于我的对象的所有实例总是大小相同。

所以我的问题是如何创建我的DataGridViewTextBoxColumn来为此列表中的每个项目创建一列?

下面是我的目标代码,该代码已针对此问题进行了简化。在语言中,Dictionary将类似于:

  • “英语”,“你好”
  • “德语”,“你好”
  • “西班牙语”,“Hola”

理想情况下,密钥将显示为列名。

看起来像这样(每一行都是一个StringItem):

Example

public class StringItem
{
    #region Attributes ########################################################################
    string name;    // String name, used to generate the enum for referencing
    string comment; // Helpful description of the string item.
    Dictionary<string, string> languages = new Dictionary<string, string>(); // For language strings.
    #endregion

    #region Public Functions ##################################################################
    public string Name
    {
        get { return name; }
    }

    public string Comment
    {
        get { return comment; }
        set { comment = value; }
    }

    public Dictionary<string, string> Languages
    {
        get { return languages; }
        set { languages = value; }
    }
    #endregion
}

更新 我相信评论中建议的链接并不是试图达到完全相同的目的,但它很有用。

我可以看到通过将以下代码添加到我的StringItem中,我可以直接访问执行myObj["English"]的语言字典

    public string this[string key]
    {
        get
        {
            return languages[key];
        }
        set
        {
            languages[key] = value;
        }
    }

然而,对于每一列,DataPropertyName并不是很有效。我认为它使用反射?任何人都可以确认这一点,并告诉我是否可以实现我自己的反射,或者DataPropertyName正在使用的任何东西,以获取我的字典项。

这是我设置列的方式:

        DataGridViewColumn column = new DataGridViewTextBoxColumn();
        column.DataPropertyName = "Name";
        column.Name = "Name";
        dgvStrings.Columns.Add(column);

        foreach (string lang in ProjectSettings.Languages)
        {
            column = new DataGridViewTextBoxColumn();
            column.DataPropertyName = lang; // <<<< THIS ISN'T WORKING.
            column.Name = lang;
            dgvStrings.Columns.Add(column);
        }

2 个答案:

答案 0 :(得分:0)

您可以遍历列表并为每个项目添加ColumnHeader。

示例:

foreach ( var item in list )
{
    someDataGridView.Columns.Add(item + "ColumnHeader", item);
}

<强>解释
您可以通过编程方式添加列。第一个参数是Column nameitem + "ColumnHeader"在这种情况下,第二个参数是Column text,例如。显示的文字,在这种情况下为item,因此如果German为标题。

答案 1 :(得分:0)

您可以为类属性和语言创建包含DataTable列,然后在DataGridView中修改数据表后,将其还原为List<StringItem>

为此,我想你有StringItem。我只是重构了你的代码以使它更干净:

public class StringItem
{
    public static string[] LanguageNames
    {
        get { return new[] { "English", "German", "Spanish" }; }
    }
    public StringItem(string name)
    {
        Name = name;
        Languages = new Dictionary<string, string>();
        LanguageNames.ToList().ForEach(x => Languages.Add(x, null));
    }
    public string Name { get; private set; }
    public string Comment { get; set; }
    public Dictionary<string, string> Languages { get; set; }
}

然后创建将List<StringItem>转换为DataTable的方法,反之亦然:

public static class StringItemExtensions
{
    public static DataTable ToDataTable(this List<StringItem> list)
    {
        var dt = new DataTable();
        dt.Columns.Add("Name").ReadOnly = true;
        dt.PrimaryKey = new DataColumn[] { dt.Columns["Name"] };
        dt.Columns.Add("Comment");
        StringItem.LanguageNames.ToList().ForEach(x => dt.Columns.Add(x));
        list.ForEach(item =>
        {
            var values = new List<object>();
            values.Add(item.Name);
            values.Add(item.Comment);
            values.AddRange(item.Languages.Values.Cast<string>());
            dt.Rows.Add(values.ToArray());
        });
        return dt;
    }
    public static List<StringItem> ToStringItemList(this DataTable table)
    {
        return table.AsEnumerable().Select(row =>
        {
            var item = new StringItem(row.Field<string>("Name"));
            foreach (var lang in StringItem.LanguageNames)
                item.Languages[lang] = row.Field<string>(lang);
            return item;
        }).ToList();
    }
}

现在,您可以在List<StringItem>中修改DataGridView

var list = new List<StringItem>();
list.Add(new StringItem("Key1"));
list.Add(new StringItem("Key2"));
list.Add(new StringItem("Key3"));
this.dataGridView1.DataSource = list.ToDataTable();

完成编辑后,足以将数据表导出到List<StringItem>

var list = ((DataTable)this.dataGridView1.DataSource).ToStringItemList();