Reputation: 434
I have an object like so
public class Person{
public int ID { get; set; }
public string Name{ get; set; }
public string Surname{ get; set; }
public List<int> AltIDs { get; set; }
public List<string> AltNames{ get; set; }
}
I am setting data into the DataGridView
like
dataGridView1.DataSource = null;
dataGridView1.DataSource = persons; // persons is List<Person>
However I only see 3 columns in the DataGridView
that is of ID, Name and Surname, the properties with List<int>
and List<string>
seem to be ignored.
Is there a way to get theses properties showing up in the DataGridView
? Probably like comma seperated values.
Upvotes: 1
Views: 940
Reputation: 9469
From what I can tell, this appears as a fairly basic “Master/Slave” type UI. In the grid, there is a “Person” object with the ID
, Name
and Surname.
Obviously from your question, the AltIDs
and AltNames
Lists
are NOT displayed in the grid.
This is due to the fact that the grid has a problem trying to add a “list of multiple” values into a “single” cell. As suggested, it is possible for you to “combine” the values into a “single” string and use that. However, this is extra work on your part and may create more work if the cell is edited.
One issue in this example is that, the AltIDs
list for each Person
could and will have a different number of elements. One possible solution is to simply ADD theses as new rows where the Person info (ID, Name and Surname) are duplicated. This will work but IMHO not very user friendly. The combo box option will also work, however again it may be confusing to users since a combo box “usually” indicates that the users selects a “single” value from many.
It is also possible to “flatten” each person object and have a column for each AltID
in the list. This will work but the possibility of large gaps in the grid are likely. Again, not very user friendly. This is all doubled by the fact that there is another list AltNames
that we have to take into account.
Given this, it appears clear that YOU are going to have to do extra work UNLESS you use an advanced third-party grid OR add more grids to the picture… in this case three (3) total. One for the person, another for the IDs and a third for the Names. Proper arrangement of the grids may be a little work, however, with three grids, it will make all the issues described above… go away. In addition the coding will be much easier.
It would be such that the user “selects” a Person
from the first grid, then the second grid list all the AltID
values and the third grid lists all the AltName
values. If the “same” data source is used for each grid then… when the user selects a different Person
in the person grid, the AltID
grid and AltName
grid will “automatically” update/refresh with the proper values. This will also make CRUD operations on any grid/value much easier.
The only problem I seen in the current Person
class is that the two Lists
are of “primitive” types. Used this way, the lists won’t display properly, the grid wants a CLASS. Therefore, you need to make a wrapper class for the AltID
and AltName
lists. Then change the list values in the Person
class. Something like…
public class AltID_C {
public int AltID { get; set; }
}
public class AltName_C {
public string AltName { get; set; }
}
public class Person {
public int ID { get; set; }
public string Name { get; set; }
public string Surname { get; set; }
public List<AltID_C> AltIDs { get; set; }
public List<AltName_C> AltNames { get; set; }
}
With this, all that is needed is to set each grid to the “same” data source, then set the AltID
grids DataMember
to the “AltIDs” property and set the AltNames
grids DataMember
to the “AltNames` property. Something like…
List<Person> AllPersons;
public Form1() {
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e) {
AllPersons = GetRandomData(25);
dgvPerson.DataSource = AllPersons;
dgvAltID.DataSource = AllPersons;
dgvAltID.DataMember = "AltIDs";
dgvAltNames.DataSource = AllPersons;
dgvAltNames.DataMember = "AltNames";
}
Additional code below to complete the example.
private List<Person> GetRandomData(int numberOfPersons) {
List<Person> listOPeople = new List<Person>();
Person curPerson;
Random rand = new Random();
for (int i = 0; i < numberOfPersons - 1; i++) {
curPerson = new Person() {
ID = rand.Next(1, 1000),
Name = "Name_" + i + 1,
Surname = "Sname_" + i + 1,
AltIDs = GetRandomNumberOfInts(rand),
AltNames = GetRandomNumberOfStrings(rand)
};
listOPeople.Add(curPerson);
}
return listOPeople;
}
private List<AltID_C> GetRandomNumberOfInts(Random rand) {
List<AltID_C> listOInts = new List<AltID_C>();
int numberOfInts = rand.Next(0, 10);
for (int i = 0; i < numberOfInts - 1; i++) {
listOInts.Add(new AltID_C { AltID = rand.Next(1, 10000) });
}
return listOInts;
}
private List<AltName_C> GetRandomNumberOfStrings(Random rand) {
List<AltName_C> listOStrings = new List<AltName_C>();
int numberOfStrings = rand.Next(0, 10);
for (int i = 0; i < numberOfStrings - 1; i++) {
listOStrings.Add(new AltName_C { AltName = "RandString: " + rand.Next(1, 1000) });
}
return listOStrings;
}
Hope that helps.
Upvotes: 1
Reputation: 6891
When DataGridView is bound to DataSource, it auto generates columns for it for the properties with primitive datatypes such as int, string, double etc.
For the datatypes which are collections, DataGridViewComboBoxColumn is used. This type of column is not autogenerated. You need to add such columns manually in the GridView columns collection.
For your use case following is the solution.
Add DataGridView to the form and add columns to it manually from the Form's designer view by click on Add Column. You will have to add 3 DataGridViewTextBoxColumn and 2 DataGridViewComboBoxColumn.
After adding columns, the columns would look as following.
Now while assigning DataSource to the DataGridView you need to write following code. Here IdColumn
, NameColumn
, and SurnameColumn
are the names give to columns when they were created in above steps.
dataGridView1.AutoGenerateColumns = false;
IdColumn.DataPropertyName = "ID";
NameColumn.DataPropertyName = "Name";
SurnameColumn.DataPropertyName = "Surname";
dataGridView1.DataSource = persons;
With the above code you will see Id, Name and Surname columns populated for persons in the collection but the dropdown lists in last two columns are empty.
To populate the dropdown list columns you need to add event handler for CellClick event of the DataGridView. And write following code there.
Here AltIdsColumn
and AltNamesColumn
are the names given to column when they created manually in earlier steps.
private void dataGridView1_CellClick(object sender, DataGridViewCellEventArgs e)
{
var altIdIndex = dataGridView1.Columns["AltIdsColumn"].Index;
var altNameIndex = dataGridView1.Columns["AltNamesColumn"].Index;
if (altIdIndex == e.ColumnIndex || altNameIndex == e.ColumnIndex)
{
var altIdsCell = (DataGridViewComboBoxCell)dataGridView1.Rows[e.RowIndex].Cells[altIdIndex];
var altNamesCell = (DataGridViewComboBoxCell)dataGridView1.Rows[e.RowIndex].Cells[altNameIndex];
if (altIdsCell.DataSource == null || altNamesCell.DataSource == null)
{
var person = dataGridView1.Rows[e.RowIndex].DataBoundItem as Person;
if (person != null)
{
altIdsCell.DataSource = person.AltIDs;
altNamesCell.DataSource = person.AltNames;
}
}
}
}
With this code, the dropdown list of AldIDs and AltNames columns will be populated when you click on those dropdown lists on individual rows.
I hope this will help you resolve your issue.
Upvotes: 1
Reputation: 1532
most probably the persons is null you just change your code like this code
first Solution :
your model :
public class Person
{
public int ID { get; set; }
public string Name { get; set; }
public string Surname { get; set; }
public List<int> AltIDs { get; set; }
public List<string> AltNames { get; set; }
}
PersonViewModel :
public class PersonViewModel
{
public int ID { get; set; }
public string Name { get; set; }
public string Surname { get; set; }
public int AltID { get; set; }
public string AltName { get; set; }
}
formLoad :
private void Form1_Load(object sender, EventArgs e)
{
List<Person> people = new List<Person>()
{new Person(){ ID=1,Name="a",Surname="a",AltIDs=new List<int>(){1,2,3,4 },AltNames=new List<string>(){"a","b","c" } },
new Person(){ ID=2,Name="b",Surname="b",AltIDs=new List<int>(){10,20,30,40 },AltNames=new List<string>(){"a","b","c" }},
new Person(){ ID=3,Name="c",Surname="c",AltIDs=new List<int>(){100,200,300,400 },AltNames=new List<string>(){"a","b","c" }},
new Person(){ ID=4,Name="d",Surname="d",AltIDs=new List<int>(){1000,2000,3000,4000 },AltNames=new List<string>(){"a","b","c" }},
new Person(){ ID=3,Name="e",Surname="e",AltIDs=new List<int>(){10000,20000,30000,40000 },AltNames=new List<string>(){"a","b","c" }}
};
List<PersonViewModel> pwm = new List<PersonViewModel>();
foreach (var person in people)
{
foreach(var id in person.AltIDs)
{
foreach (var name in person.AltNames)
pwm.Add(new PersonViewModel() { ID = person.ID, Name = person.Name, Surname = person.Surname, AltID = id, AltName = name });
}
}
dgv.DataSource = pwm;
}
Second Solution :
your model :
public class Person
{
public int ID { get; set; }
public string Name { get; set; }
public string Surname { get; set; }
public List<int> AltIDs { get; set; }
public List<string> AltNames { get; set; }
}
PersonViewModel :
public class PersonViewModel
{
public int ID { get; set; }
public string Name { get; set; }
public string Surname { get; set; }
public string AltID { get; set; }
public string AltName { get; set; }
}
FormLoad :
private void Form1_Load(object sender, EventArgs e)
{
List<Person> people = new List<Person>()
{new Person(){ ID=1,Name="a",Surname="a",AltIDs=new List<int>(){1,2,3,4 },AltNames=new List<string>(){"a","b","c" } },
new Person(){ ID=2,Name="b",Surname="b",AltIDs=new List<int>(){10,20,30,40 },AltNames=new List<string>(){"a","b","c" }},
new Person(){ ID=3,Name="c",Surname="c",AltIDs=new List<int>(){100,200,300,400 },AltNames=new List<string>(){"a","b","c" }},
new Person(){ ID=4,Name="d",Surname="d",AltIDs=new List<int>(){1000,2000,3000,4000 },AltNames=new List<string>(){"a","b","c" }},
new Person(){ ID=3,Name="e",Surname="e",AltIDs=new List<int>(){10000,20000,30000,40000 },AltNames=new List<string>(){"a","b","c" }}
};
List<PersonViewModel> pwm = new List<PersonViewModel>();
StringBuilder sbIds;
StringBuilder sbNames;
foreach (var person in people)
{
sbIds = new StringBuilder();
sbNames = new StringBuilder();
person.AltIDs.ForEach(c=> sbIds.Append(c.ToString()).Append(","));
person.AltNames.ForEach(c=> sbNames.Append(c).Append(","));
pwm.Add(new PersonViewModel() { ID = person.ID, Name = person.Name, Surname = person.Surname, AltID = sbIds.ToString().TrimEnd(','), AltName = sbNames.ToString().TrimEnd(',') });
}
dgv.DataSource = pwm;
}
Upvotes: 3