For my current problem I want to create a DataGridView and use a list of objects as the datasource.
The problem I'm having is that the objects itself contains two lists, which are supposed to fill combobox columns. The DataGridView should contain three columns, each corresponding to my sample object below. The first column is a simple text column, while the other two are combo box columns.
Currently I'm receiving the error:
System.ArgumentException: The value DataGridViewComboBoxCell is invalid.
I've been looking for other solutions on SO, but can't seem to get it right.
public class SampleObject
{
public SampleObject(string name, IList<TimeSpan> startTimes, IList<Activity> completedActivities)
{
this.Name = name;
this.StartTimes = startTimes;
this.CompletedActivities = completedActivities;
}
public string Name { get; }
public IList<TimeSpan> StartTimes { get; }
public IList<Activity> CompletedActivities { get; }
}
Activity object:
public class Activity
{
public Activity(string activityName)
{
ActivityName = activityName;
}
public string ActivityName { get; }
public override string ToString()
{
return ActivityName;
}
}
And the code for adding the columns to my grid:
private void FillGrid()
{
sampleGrid.AutoGenerateColumns = false;
var columnName = new DataGridViewTextBoxColumn
{
DataPropertyName = nameof(SampleObject.Name),
HeaderText = "Name",
Width = 160,
ReadOnly = true
};
sampleGrid.Columns.Add(columnName);
var columnStartTimes = new DataGridViewComboBoxColumn()
{
ValueType = typeof(TimeSpan),
HeaderText = "StartTimes",
Width = 120,
ReadOnly = false
};
sampleGrid.Columns.Add(columnStartTimes);
var columnCompletedActivities = new DataGridViewComboBoxColumn
{
ValueType = typeof(Activity),
HeaderText = "Completed activities",
Width = 120,
ReadOnly = false
};
sampleGrid.Columns.Add(columnCompletedActivities);
}
And populating the grid:
List<SampleObject> myObjects = GetSampleObjectsBasedOnValue(value);
sampleGrid.DataSource = myObjects;
FillComboBoxesInDGV(myObjects);
Method for filling the comboboxes:
private void FillComboBoxesInDGV(IList<SampleObject> sampleObjects)
{
for (int i = 0; i < sampleObjects.Count; i++)
{
DataGridViewRow row = sampleGrid.Rows[i];
var firstBox = row.Cells[1] as DataGridViewComboBoxCell;
firstBox.DataSource = sampleObjects[i].StartTimes;
var secondBox = row.Cells[2] as DataGridViewComboBoxCell;
secondBox.DataSource = sampleObjects[i].CompletedActivities;
}
}
DataPropertyName
to one of the properties of the object, this works for primitive types. However, if the property in the object is another object or “collection” (like another list) then the grid is NOT going to display this list in a combo box even if you set theDataPropertyName
. This makes sense and there are ways to fix it to make it work. However, in your description… - JohnGDataGridViewComboBoxColumn
WONT WORK in this case. Unless you add ALL the :”start times” from ALL the rows into the combo box column, you are almost guaranteed to get the error you are getting which is saying that one of the “start times” in the data is NOT one of the items in the combo boxes list of items. - JohnGList<SampleObject>
as aDataSource
to the grid, then AFTER the grid is bound to the list, you will need to loop through the GRID rows, grab the appropriateSampleObject
for that row and set eachDataGridComboBoxCell
’sDataSource
to the appropriate “StartTimes” list or “CompleteActivites” list. You should also “remove” setting the columnsDataPropertyName
except for the “Name” column. Also, setting the “whole” grid to “ReadOnly”sampleGrid.ReadOnly = true;
is going to make the combo boxes unchangeable. - JohnG