Here is an example code that should get you started.
First I create a list of values (cities) for each state. For this the Dictionary
collection comes handy:
Dictionary<string, List<string>> dict = new Dictionary<string, List<string>>();
for (int i = 0; i < dt.Rows.Count; i++)
{
string state = dt.Rows[i][0].ToString();
string city = dt.Rows[i][1].ToString();
if (! dict.Keys.Contains(state )) dict.Add(state, new List<string>());
dict[state].Add(city);
}
I loop over your table and for each row I add a new entry for the city and, if necessary, for the state.
Now we modify the setup of the DGV to use those Lists
in the Items
of each of the DataGridViewComboBoxCell
.
Note: Here the key is to use the DataGridViewComboBoxCells
, and not the DataGridViewComboBoxColumns
!
For easier access I create string variables for the state and city values again..
for (int i = 0; i < dt.Rows.Count; i++)
{
string state = dt.Rows[i][0].ToString();
string city = dt.Rows[i][1].ToString();
dataGridView1.Rows.Add();
DataGridViewComboBoxCell stateCell =
(DataGridViewComboBoxCell)(dataGridView1.Rows[i].Cells[0]);
stateCell.Items.AddRange(dict.Keys.ToArray());
stateCell.Value = state;
DataGridViewComboBoxCell cityCell =
(DataGridViewComboBoxCell)(dataGridView1.Rows[i].Cells[1]);
cityCell.Items.AddRange(dict[state].ToArray());
cityCell.Value = city;
}
Note: This sets up the values in the DropDowns, but after each change in a 'State' column you will need to adapt the 'Cities' column in that row! Therefore it would be a good idea to make the Dictionary
persistent by moving it to class level and to create a little function you can call after such a change.
Here is an example of this functionality:
private void dataGridView1_CellValueChanged(object sender, DataGridViewCellEventArgs e)
{
if (e.ColumnIndex == 0)
setCities(e.RowIndex, dataGridView1.Rows[e.RowIndex].Cells[0].Value.ToString());
}
void setCities(int row, string state)
{
DataGridViewComboBoxCell cityCell =
(DataGridViewComboBoxCell)(dataGridView1.Rows[row].Cells[1]);
cityCell.Items.Clear();
cityCell.Items.AddRange(dict[state].ToArray());
cityCell.Value = cityCell.Items[0];
}
Note that the new cityCell.Value
shows up only after leaving the edited cell!
Final note: If you really want to display only one row per state, you need to change the loop that fills the DGV
to loop not over your table but over the dict.Keys
collection:
for (int i = 0; i < dict.Keys.Count; i++)
{
string state = dict.Keys.ElementAt(i);
string city1 = dict[state][0].ToString();
dataGridView1.Rows.Add();
DataGridViewComboBoxCell stateCell =
(DataGridViewComboBoxCell)(dataGridView1.Rows[i].Cells[0]);
stateCell.Items.AddRange(dict.Keys.ToArray());
stateCell.Value = state;
DataGridViewComboBoxCell cityCell =
(DataGridViewComboBoxCell)(dataGridView1.Rows[i].Cells[1]);
cityCell.Items.AddRange(dict[state].ToArray());
cityCell.Value = city1;
}