• Welcome to TechPowerUp Forums, Guest! Please check out our forum guidelines for info related to our community.
  • The forums have been upgraded with support for dark mode. By default it will follow the setting on your system/browser. You may override it by scrolling to the end of the page and clicking the gears icon.

Fun with DataGridViewComboBoxColumn C#

Kreij

Senior Monkey Moderator
Joined
Feb 6, 2007
Messages
13,817 (2.07/day)
Location
Cheeseland (Wisconsin, USA)
Just when you thought old Uncle Kreij was cloistered away in his computer room playing Sacred II ....

Let's say that you are happily coding away (coding should aways be a happy thing, if it's not, take a break and go play Sacred II), and you realize that you need a DataGridView that contains a couple of ComboBoxes in the columns. No problem, you think, I'll just use the handy DataGridViewComboBoxColumn, but then your realize that the contents of the second ComboBox Cell is dependent upon the value selected in the first ComboBox Cell.

No big deal, you quip, for I shall just trap the OnSelectedIndexChanged event that all ComboBoxes have exposed. Then you break out in a cold sweat, hands shaking, as you realize that the only method that MicroSoft chose to expose for the DataGridViewComboBoxColumn class is .... (drum roll) .... Dispose(). :wtf:

Fear not, stop your wailing and gnashing of teeth for I shall show you a little tidbit that will help make your life easier.

The following code assumes that you have a DataGridView called "myDataGridView", and that it contains two ComboBox columns called "CBColumn1" and "CBColumn2", and that the column indices are 0 and 1 respectively. ComboBox one will contain two items, "Show List One" and "Show List Two". It also uses three Lists of KeyValuePairs called "MainList" (which is the items in the first column and not used in this code), "ListOne" and "ListTwo". I use List of this type to hold static database content so I only have to open the connection to the database server once, and can play with the data in the lists easily. I could have done the same thing with DataSets, but Lists are more fun.

The KeyValuePairs contain an integer (Key) and a string (Value). We will not be using the "Key" in this example, only the "Value" which we will put in the ComboBox as items. I'm not going to go into the detail of creating these types of lists, but if you would like to know more just post in this thread and I will elaborate.

To find out if the value of the first ComboBox changed, you need to trap on the DataGridView's "CurrentCellDirtyStateChanged" event. Then check to see if the current cell is, in fact, dirty. Following that, check for a specific value in the ComboBox and feed the appropriate list into the second ComboBox. We will also check to make sure that the second ComboBox contains no items before we fill it otherwise you will get both lists in the second ComboBox and it will continue to grow every time you switch selections in the first ComboBox.

Okay, let's show some code.
Code:
[color="Blue"]private void[/color] myDataGridView_CurrentCellDirtyStateChanged([color="Blue"]object[/color] sender, [color="Teal"]EventArgs[/color] e)
{
    [color="Blue"]if[/color] (myDataGridView.IsCurrentCellDirty)
    {
        myDataGridView.CommitEdit([color="Teal"]DataGridViewDataErrorContexts[/color].Commit);
        [color="Blue"]if[/color] (myDataGridView.CurrentRow.Cells.IndexOf(myDataGridView.CurrentCell) == 0)
        {
            [color="Blue"]if[/color] (myDataGridView.CurrentCell.Value == [color="red"]"Show List One"[/color])
            {
                [color="Teal"]DataGridViewComboBoxColumn[/color] Col2 = ([color="Teal"]DataGridViewComboBoxColumn[/color])myDataGridView.Columns[[color="Red"]"CBColumn2"[/color]];
                [color="Blue"]if[/color] (Col2.Items.Count != 0) Col2.Items.Clear();
                [color="Blue"]foreach[/color] ([color="Teal"]KeyValuePair[/color]<[color="Blue"]int[/color], [color="Blue"]string[/color] Item [color="Blue"]in[/color] ListOne)
                {
                    Col2.Items.Add(Item.Value);
                }
            }
            [color="Blue"]else[/color]  [color="Green"]// "Show List Two" was selected[/color]
            {
                [color="Teal"]DataGridViewComboBoxColumn[/color] Col2 = ([color="Teal"]DataGridViewComboBoxColumn[/color])myDataGridView.Columns[[color="Red"]"CBColumn2"[/color]];
                [color="Blue"]if[/color] (Col2.Items.Count != 0) Col2.Items.Clear();
                [color="Blue"]foreach[/color] ([color="Teal"]KeyValuePair[/color]<[color="Blue"]int[/color], [color="Blue"]string[/color] Item [color="Blue"]in[/color] ListTwo)
                {
                    Col2.Items.Add(Item.Value);
                }
            }
        }
    }
}

Piece of Cake! Now some of you may be thinking, why not just trap on the CellValueChanged event of the DataGridView?
That will work, but the event does not fire until you leave the cell which may not be soon enough for certain applications.

Hope my little foray into DataGridViewComboBoxColumn will help someone at some point.
In the mean time ... Happy Coding !!
 
Last edited:
Sigh ... after a long day of coding, I have coding on the brain tonight. I should be playing games. It's a Friday night after all......

Reducing the code you have to type has always been a kind of challenge for me (I am the worst critic of my own code) so here is another way to write the inner portion of that method will less typing.

Let's move our local copy of the DataGridViewComboBoxColumn up so we only have to declare it once. Doing that means we only have to clear our items once also.

(No color coding this time)
Code:
private void myDataGridView_CurrentCellDirtyStateChanged(object sender, EventArgs e)
{
    if (myDataGridView.IsCurrentCellDirty)
    {
        myDataGridView.CommitEdit(DataGridViewDataErrorContexts.Commit);
        DataGridViewcomboBoxColumn Col2 =
            (DataGridViewComboBoxColumn)myDataGridView.Columns["CBColumn2"];
        if (Col2.Items.Count != 0) Col2.Items.Clear();
        foreach (KeyValuePair<int, string> Item in 
            (myDataGridViewCurrentCell.Value.ToString() == 
            "Show List One" ? ListOne : ListTwo) 
            Col2.Items.Add(Item.Value);
    }
}

I must admint I didn't run this through the debugger, but it should work.
Much shorter, cleaner and best of all ... more obscure. Job Security FTW !!! :laugh:
 
Back
Top