I am successfully binding to a list of objects and setting this as the DataGridViews datasource. Definiting columns, at run time, which include the appropriate DataPropertyNames.
However I now need to add a list to my object class. The size of this list is dynamic, but always the same size for all instances of my object.
So my question is how can I create my DataGridViewTextBoxColumn to create a column for each items within this list?
Below is my object code, which has been simplified for this question. Within the languages Dictionary will be something like:
Ideally the Key would appear as the column name.
Looking like this (each row is a 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
}
Update: I believe the suggested link in the comments isn't trying to achieve quite the same thing, however it is useful.
I can see that by adding the follow code to my StringItem I can directly access the language dictionary doing myObj["English"]
public string this[string key]
{
get
{
return languages[key];
}
set
{
languages[key] = value;
}
}
However the DataPropertyName, for each column, doesn't quite work liek this. I assume it uses reflections? Can anyone confirm this and tell me if I can implement my own reflection, or whatever DataPropertyName is using, to get my dictionary item.
This is how I set up the columns:
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);
}
You could iterate through your list and add a ColumnHeader for each item.
Example:
foreach ( var item in list )
{
someDataGridView.Columns.Add(item + "ColumnHeader", item);
}
Explanation:
You can add columns programmatically. The first argument being the Column name
, item + "ColumnHeader"
in this case and the 2nd is Column text
eg. displayed text, in this case item
so if it was German
that would be the header.
You can create a DataTable
containing columns for your class properties and languages, then after editing the data table in DataGridView
, revert it back to List<StringItem>
.
To do so, I suppose you have StringItem
. I just refactored your code to make it more clean:
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; }
}
Then create methods to convert List<StringItem>
to a DataTable
and vice versa:
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();
}
}
Now you can edit a List<StringItem>
in 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();
After finish editing, it's enough to export the data table to a List<StringItem>
:
var list = ((DataTable)this.dataGridView1.DataSource).ToStringItemList();
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.