【问题标题】:DataGridView bind to a list of Objects which contain a DictionaryDataGridView 绑定到包含字典的对象列表
【发布时间】:2017-03-08 12:38:14
【问题描述】:

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

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

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

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

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

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

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

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
}

更新: 我相信 cmets 中建议的链接并没有试图实现完全相同的目标,但它很有用。

我可以看到,通过将以下代码添加到我的 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);
        }

【问题讨论】:

  • 是的,这看起来很有趣。我现在在 StringItem 类中实现了一个访问器,它使用键“公共字符串 this[string key]”,然后在创建列时放置一个 foreach 循环为每种语言创建一个列并将 DataPropertyName 设置为语言键。但这实际上并不是获取或设置值!是因为我实现了 TryGetMember 和 TrySetMember 函数?
  • @lok​​usking 正如链接代码所暗示的那样,我已经更新了我的 StringItem 以从 DynamicObject 继承,然后覆盖 TryGetMemberTrySetMember 以便当行请求一种语言时,由 DataPropertyName 定义列我可以返回字典条目。然而,在 TryGetMember 函数中设置一个断点,它永远不会被击中!这是 DataPropertyName 应该触发的吗?
  • @TheGrovesy 我知道这个问题很老了,但作为未来读者和你未来项目的记录,你可以在运行时和编辑后使用将你的班级塑造成DataTable ,将其还原为List&lt;StringItem&gt;。我发布了执行这种转换的代码。

标签: c# .net winforms datagridview datasource


【解决方案1】:

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

示例:

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

说明:
您可以以编程方式添加列。在这种情况下,第一个参数是Column nameitem + "ColumnHeader",第二个参数是Column text,例如。显示的文本,在本例中为 item,所以如果是 German,那将是标题。

【讨论】:

  • 但是他们不会被绑定吧?
  • 啊没想到我会检查一个方法:)
  • 我只为您找到了dataGridView1.AutoGenerateColumns = false;,我认为在这种情况下您应该自己填充 dataGridView 并像我一样制作列。
【解决方案2】:

您可以创建一个DataTable,其中包含您的类属性和语言的列,然后在编辑DataGridView 中的数据表后,将其恢复为List&lt;StringItem&gt;

为此,我想你有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&lt;StringItem&gt; 转换为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();
    }
}

现在您可以在DataGridView 中编辑List&lt;StringItem&gt;

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&lt;StringItem&gt;即可:

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

【讨论】:

    猜你喜欢
    • 2014-08-18
    • 1970-01-01
    • 2012-03-27
    • 1970-01-01
    • 2010-10-25
    • 2013-08-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多