# VBForums CodeBank > CodeBank - Visual Basic .NET >  [.NET 2.0+] Adding a ComboBox Column to a DataGridView

## jmcilhinney

I seem to keep answering this question so I figured a CodeBank submission was warranted.

Stage 1.
1. Create a new WinForms application project.
2. Add a DataGridView to the form.
3. Add a BindingSource to the form.
4. Add the following code:

```
Private Sub Form1_Load(ByVal sender As Object, _
                       ByVal e As EventArgs) Handles MyBase.Load
    Me.BindingSource1.DataSource = Me.GetChildTable()
    Me.DataGridView1.DataSource = Me.BindingSource1
End Sub

Private Function GetChildTable() As DataTable
    Dim table As New DataTable

    With table.Columns
        .Add("ChildID", GetType(Integer))
        .Add("ParentID", GetType(Integer))
        .Add("ChildName", GetType(String))
    End With

    With table.Rows
        .Add(1, 3, "Child 1")
        .Add(2, 2, "Child 2")
        .Add(3, 1, "Child 3")
    End With

    Return table
End Function
```

Now run the project.  Notice that the grid contains three TextBox columns.  That is the default for most types of data.  If you want a different column type for such data then you have to add the column yourself.  Here's how to do that for a column of ComboBoxes.

Stage 2.
1. Add a second BindingSource to the form.
2. Select the DataGridView and expand the smart tag (the little arrow at the top, right).
3. Click "Add Column".
4. Change the Type to DataGridViewComboBoxColumn.
5. Click "Add".
6. Click "Close".
7. Expand the smart tag again.
8. Click "Edit Columns".
9. Set the DataPropertyName of Column1 to "ParentID".
10. Click "OK".
11. Delete the previous code and add the following:

```
Private Sub Form1_Load(ByVal sender As Object, _
                       ByVal e As EventArgs) Handles MyBase.Load
    Me.BindingSource2.DataSource = Me.GetParentTable()
    Me.Column1.DisplayMember = "ParentName"
    Me.Column1.ValueMember = "ParentID"
    Me.Column1.DataSource = Me.BindingSource2

    Me.BindingSource1.DataSource = Me.GetChildTable()
    Me.DataGridView1.DataSource = Me.BindingSource1
End Sub

Private Function GetParentTable() As DataTable
    Dim table As New DataTable

    With table.Columns
        .Add("ParentID", GetType(Integer))
        .Add("ParentName", GetType(String))
    End With

    With table.Rows
        .Add(1, "Parent 1")
        .Add(2, "Parent 2")
        .Add(3, "Parent 3")
    End With

    Return table
End Function

Private Function GetChildTable() As DataTable
    Dim table As New DataTable

    With table.Columns
        .Add("ChildID", GetType(Integer))
        .Add("ParentID", GetType(Integer))
        .Add("ChildName", GetType(String))
    End With

    With table.Rows
        .Add(1, 3, "Child 1")
        .Add(2, 2, "Child 2")
        .Add(3, 1, "Child 3")
    End With

    Return table
End Function
```

Now run the project again.  There are several things to note here:

1. The grid still only contains three columns but one of them contains ComboBoxes.

That's because, by setting the DataPropertyName of the column, you told it to bind to that column of the grid's DataSource.  As such a new column was not added to the grid for that column of the DataSource.

2. The columns are not in the same order as they were before.

You can force the columns to be displayed in the order you want by adding them all at design time and not relying on the grid to auto-generate any of them.  You can also mess with the DisplayIndex properties of each column but that is something for you to play with.

3. The ParentID column now shows the ParentName values from the parent table, rather than the ParentID values from the child table.

This is a function of having set the DisplayMember of the column, which determines which column from it's DataSource gets displayed.

----------


## jmcilhinney

Lets look at the path of the data through the grid, the column, the cells and the ComboBoxes.  First up, the DataSource of the grid and the DataSource of the column are two different things.  The grid's DataSource controls what data gets assigned to the Value property of each cell.  The column's DataSource controls what gets displayed in the drop-down lists in the cells.

Normally your combo box column doesn't contain any ComboBoxes.  What you see is simply drawn in the cell.  When you put a cell into edit mode, e.g. by clicking the down arrow, the grid will reuse an existing ComboBox control if there is one, otherwise it will create a new one.  The DataSource, DisplayMember and ValueMember property values of the column are all pushed down to the cell, which in turn pushes them to the ComboBox control.  As such, the binding is done in exactly the same way as it would in a regular ComboBox.  The cell then pushes its Value property to the ComboBox's SelectedValue property.  The ComboBox is then embedded in the cell and its drop-down list displayed.

When the user makes a selection it's only the embedded ComboBox that changes.  The underlying cell is unaffected at this stage, which is always the way with a DataGridView.  When the user presses Enter or leaves the cell, the ComboBox's SelectedValue is then pushed to the cell's Value property and the ComboBox removed from the cell.

----------


## kuldevbhasin

thankx for the code jmc i have used it and have got it working.
i have created a combobox col. in datagridview containing the codes for a category but i am not able to get the code that has been selected 
for e.g. say i have created a col. Part2CategoryCode how do i get the selected code in the combobox.?? 
pls. help.thankx

----------


## jmcilhinney

> thankx for the code jmc i have used it and have got it working.
> i have created a combobox col. in datagridview containing the codes for a category but i am not able to get the code that has been selected 
> for e.g. say i have created a col. Part2CategoryCode how do i get the selected code in the combobox.?? 
> pls. help.thankx


To get the value of a cell in a DataGridView you get the cell's Value property, regardless of the type of the cell.

----------


## kuldevbhasin

thankx jmc i got the part of selecting the code working ...but then in the smae option i have a method where the user can double click the row and select the category from a detailed help where he can see the category code, name and the details ....now once the user selects the category from here i want that the text of the combobox col. too should show the same data..
i tried the followings


```
 Dim mCC As String = row("CatCode") ' The value of mCC is as expected 
 Dim mIIdx As Integer = Me.Part2CategoryCode.Items.IndexOf(mCC)
 dgPart2.Columns("CategoryCode").DisplayIndex = mIIdx
```

miidx comes as -1 as it cant find the item....i have tried a many more things but being a dumbo as i am cant get anything out of it.....
pls. help me out...thankx

----------


## jmcilhinney

> thankx jmc i got the part of selecting the code working ...but then in the smae option i have a method where the user can double click the row and select the category from a detailed help where he can see the category code, name and the details ....now once the user selects the category from here i want that the text of the combobox col. too should show the same data..
> i tried the followings
> 
> 
> ```
>  Dim mCC As String = row("CatCode") ' The value of mCC is as expected 
>  Dim mIIdx As Integer = Me.Part2CategoryCode.Items.IndexOf(mCC)
>  dgPart2.Columns("CategoryCode").DisplayIndex = mIIdx
> ```
> ...


You're trying to make this complicated when it's really very simple.  You need to keep in mind that what you see in the grid is NOT necessarily what the data bound to it actually contains.  Remember, the DataTable bound to the grid actually contains foreign key values in that column.  The data you see is the corresponding friendly name from the related table.  It is NOT the data bound to the grid.

So, every cell in the grid has a Value property and that corresponds to the value of the field from the data source that is bound to that cell.  If you want to change something in code it is THAT that you change.  You don't go and get the friendly name from the related table.  You get the ID.  You assign that ID to the Value property of the cell and the UI will update automatically.

To demonstrate this in action, follow all the instructions in the first post of this thread.  Now, add a Button to your form and add the following code:

```
Private Sub Button1_Click(ByVal sender As Object, _
                          ByVal e As EventArgs) Handles Button1.Click
    Me.DataGridView1("Column1", 0).Value = 2
End Sub
```

Now run the project and notice that the cell in the top, left corner displays the text "Parent 3".  That is the friendly name from the Parent table but the Value of the cell is actually just the number 3, which is the ID that corresponds to "Parent 3".  Now click the Button.  Notice the text in the cell change?  You changed the Value of the cell to the number 2 and the displayed text is "Parent 2", which is the friendly name from the Parent table that corresponds to the ID you set.

----------


## kuldevbhasin

thankx a lot jmc ...u have always been a great help to me....thankx

----------


## szlamany

I was directed to this thread by a forum member - I had asked if I could take a DATABOUND DATAGRIDVIEW - and make one of the BOUND column become a COMBOBOX.

But I'm not seeing how to change the "columntype" for an existing column.

Which leads me to believe I have to "hide" the DATABOUND column and add a "fake" column that is a combobox - and relate the two columns in code events.

Does that make sense?

----------


## jmcilhinney

> I was directed to this thread by a forum member - I had asked if I could take a DATABOUND DATAGRIDVIEW - and make one of the BOUND column become a COMBOBOX.
> 
> But I'm not seeing how to change the "columntype" for an existing column.
> 
> Which leads me to believe I have to "hide" the DATABOUND column and add a "fake" column that is a combobox - and relate the two columns in code events.
> 
> Does that make sense?


You can't change the type of a column once it's been created.  You need to create the combo box column BEFORE binding the data and tell it which data source column to bind to by setting its DataPropertyName.  That way the specified data source column will bind to your combo box column instead of creating a new text box column.  It's all in the first post.

----------


## jmcilhinney

I also mention the DisplayIndex in post #1. I don't know all the why and how but I should mention that using this may not be exactly as you'd expect. It seems to me that the column you add at design time is not actually the column you end up seeing. As such, you cannot refer to the column using the member variable after binding your data. If you want to change the position of your combo box column you need to index the grid's Columns collection to get a reference.

Further to this, let's address the following point from post #1:


> 2. The columns are not in the same order as they were before.
> 
> You can force the columns to be displayed in the order you want by adding them all at design time and not relying on the grid to auto-generate any of them. You can also mess with the DisplayIndex properties of each column but that is something for you to play with.


Starting off with the same project as it was at the end of post #1, the IDE creates a member variable named 'Column1' when you add the combo box column in the designer.  As such, you might think you could rearrange the columns by setting the DisplayIndex through that member variable, like so:

```
Private Sub Form1_Load(ByVal sender As Object, _
                       ByVal e As EventArgs) Handles MyBase.Load
    Me.BindingSource2.DataSource = Me.GetParentTable()
    Me.Column1.DisplayMember = "ParentName"
    Me.Column1.ValueMember = "ParentID"
    Me.Column1.DataSource = Me.BindingSource2

    Me.BindingSource1.DataSource = Me.GetChildTable()
    Me.DataGridView1.DataSource = Me.BindingSource1

    Me.Column1.DisplayIndex = 1
End Sub
```

That's what I thought, but I was wrong.  It appears that the object referred to by the Column1 variable is not the actual column you see when you run the project.  I believe that the original column is cloned and the clone is displayed.  I'm yet to confirm that and, if it's true, I've no idea why it's done that way.  Anyway, what you need to do is to refer to the actual column that is displayed by index, then set its DisplayIndex.  Note that setting the DisplayIndex changes the order in which the columns are displayed but it does NOT change the order of the Columns collection of the grid and thus does not change the Index properties of the columns themselves.

Now, another odd point to note is that the columns themselves are actually in the grid's Columns collection in the same order as the columns they are bound to in the data source.  As such, in this case what we really want is for the DisplayIndex of each column to match its Index.  To this end, we can move the combo box column back to its original position between the two text box columns by changing the Load event handler to this:

```
Private Sub Form1_Load(ByVal sender As Object, _
                       ByVal e As EventArgs) Handles MyBase.Load
    Me.BindingSource2.DataSource = Me.GetParentTable()
    Me.Column1.DisplayMember = "ParentName"
    Me.Column1.ValueMember = "ParentID"
    Me.Column1.DataSource = Me.BindingSource2

    Me.BindingSource1.DataSource = Me.GetChildTable()
    Me.DataGridView1.DataSource = Me.BindingSource1

    For Each column As DataGridViewColumn In Me.DataGridView1.Columns
        column.DisplayIndex = column.Index
    Next
End Sub
```

----------


## MaslowB

I'm in Visual studio 2008 .net 3.5 c#.About stage 2 step 9: When I click edit columns the DataPropertyName drop down has nothing available in it besides none. I typed in the requested value and then the rest of the code, and the form loads and appears just fine, but clicking the combo boxes does not list the other possible values. Is this as intended for your example or is there a bug?

----------


## jmcilhinney

> I'm in Visual studio 2008 .net 3.5 c#.About stage 2 step 9: When I click edit columns the DataPropertyName drop down has nothing available in it besides none.


There would only be options in the DataPropertyName drop-down if you had bound the grid to a typed DataSet in the designer.  If you're not setting the grid's DataSource until run time then the designer has no idea what columns will be available to bind to so it can't provide a list.


> I typed in the requested value and then the rest of the code, and the form loads and appears just fine, but clicking the combo boxes does not list the other possible values. Is this as intended for your example or is there a bug?


It sounds like you either haven't set the combo box column's DataSource or else you haven't populated the DataTable that you've bound to it.  In my code the combo boxes are bound to BindingSource2, which is bound to the parent DataTable.

----------


## MaslowB

I ripped down the example and used it as a template for the actual work I needed the combobox for, and it worked just fine. So clearly I must have made a mistake somewhere. I built a snippet from the result, hopefully it's helpful on the C# code bank.

----------


## ralstoj

Hi

I am trying to set a form in vb.net that reads in an xml file to a datagridview with combobox columns and then lets the user update the data in the datagrid view with information from the comboboxes and then save the data as an updated xml file. I have run into a number of problems in my understanding of now vb.net works and getting this to work.

1. To start with I was setting up the xml file as a dataset and reading that in to the datagrid but was unable to get the columns created by this process to turn into combobox columns. From what I have read this can not be done? So to work around this using your code above I have considering loading the xml into a table and then into the datagrid. Is this the best way to do this?

2. Before going down this track I am using your example above and I am trying to write out and xml file of the updated data in the datagrid on the form close event I have tried adding the following to save the changes 

        'save any edits in the datagridview to the BindingSource
        Me.BindingSource1.EndEdit()

but now I need to know how to convert the updated bindingsource to a dataset and use the writexml function to export out the updated data to xml are you able to give an example of how you would do this.

Regards



Justin Ralston

----------


## jmcilhinney

> Hi
> 
> I am trying to set a form in vb.net that reads in an xml file to a datagridview with combobox columns and then lets the user update the data in the datagrid view with information from the comboboxes and then save the data as an updated xml file. I have run into a number of problems in my understanding of now vb.net works and getting this to work.
> 
> 1. To start with I was setting up the xml file as a dataset and reading that in to the datagrid but was unable to get the columns created by this process to turn into combobox columns. From what I have read this can not be done? So to work around this using your code above I have considering loading the xml into a table and then into the datagrid. Is this the best way to do this?
> 
> 2. Before going down this track I am using your example above and I am trying to write out and xml file of the updated data in the datagrid on the form close event I have tried adding the following to save the changes 
> 
>         'save any edits in the datagridview to the BindingSource
> ...


My code binds DataTables.  If you have an XML file and you're reading it into a DataSet by calling DataSet.ReadXml then you've got DataTables, so you simply use the very same principles my code demonstrates.  To save the data you call DataSet.WriteXml.

----------


## ralstoj

Hi 

I have updated my code as below but get an error
Datagridviewcomboboxcell not valid? do I have to have the 
values in the combobox cell as integers and match those I am uploading in from the xml with and ID key is it possible to have different values?

Justin


Private Sub Form1_Load(ByVal sender As Object, _
                           ByVal e As EventArgs) Handles MyBase.Load

        Dim ds As New DataSet
        '  use filestream class to read xml content.
        Dim streamRead As New System.IO.FileStream("f:\New Folder\ProfileViewTypes.xml", _
        System.IO.FileMode.Open)

        'Dataset can read content from FileStream.
        ds.ReadXml(streamRead)

        'Table Format in XML file
        '<ProfileViewType>
        'Column1 =     '        <Name>Road Long Section</Name>
        'Column2 =     '        <ProfilestyleEx>E-gl</ProfilestyleEx>
        'Column3 =     '        <ProfilestylePr>P-gl</ProfilestylePr>
        'Column4 =     '        <ProfileViewStyle>Roadx5</ProfileViewStyle>
        '</ProfileViewType>

        'adds the contents to the combobox dropdown
        Me.BindingSource2.DataSource = Me.GetParentTable()
        Me.Column1.DisplayMember = "StyleName"
        Me.Column1.ValueMember = "StyleID"
        Me.Column1.DataSource = Me.BindingSource2

        ''  Bind data to your control.
        'Me.BindingSource1.DataSource = Me.GetChildTable()
        'Me.DataGridView1.DataSource = Me.BindingSource1

        'add data from xml file to datagrid
        Me.DataGridView1.DataSource = ds.Tables(0)

        ' Close FileStream object
        streamRead.Close()

    End Sub

    Private Function GetParentTable() As DataTable
        Dim table As New DataTable

        With table.Columns
            .Add("StyleID", GetType(Integer))
            .Add("StyleName", GetType(String))
        End With

        With table.Rows
            .Add(1, "Section")
            .Add(2, "Style 2")
            .Add(3, "Style 3")
            .Add(4, "Import Style")
        End With

        Return table
    End Function

    Private Function GetChildTable() As DataTable
        Dim table As New DataTable

        With table.Columns
            .Add("ChildID", GetType(Integer))
            .Add("StyleID", GetType(Integer))
            .Add("ChildName", GetType(String))
        End With

        With table.Rows
            .Add(1, 3, "Child 1")
            .Add(2, 2, "Child 2")
            .Add(3, 1, "Child 3")
        End With

        Return table
    End Function
End Class

----------


## rmunukutla

Excellent explanation.

----------


## vpm_sampath

Hi,
  Getting a combo box in a datagrid was very good and what i am looking for.

  But i need a depth of it.
  in ur example Parent name r shown in the first column but if i need it in the middle of the grid say 4th column  how can i do it.

 and if i select a value in the combo box i have to set the value member of the combo box to anohter column of the datagrid.

Please Help me to do in regular simple way u do it for beginners like me.

thanks & regards

----------


## jmcilhinney

> Getting a combo box in a datagrid was very good and what i am looking for.
> 
>   But i need a depth of it.
>   in ur example Parent name r shown in the first column but if i need it in the middle of the grid say 4th column  how can i do it.


That is already addressed in post #10.  Please read all the information already provided before asking questions.


> and if i select a value in the combo box i have to set the value member of the combo box to anohter column of the datagrid.


I very much doubt that you need to set the ValueMember.  Please explain exactly what it is that you want to happen.  Most likely what you want is already covered in post #6, but I'm not 100% sure because I'm not 100% sure what you want.

----------


## vpm_sampath

Hi,
 as u say its similar to post #6 but not exactly the same i ask.

 asume the displayed column is item name and valued member is itemcode i need to save only the itemcode in database and need to retrive it and display itemname. for that i need the item code of the selected name. how to do so. 

thanks for ur reply

----------


## jmcilhinney

> Hi,
>  as u say its similar to post #6 but not exactly the same i ask.
> 
>  asume the displayed column is item name and valued member is itemcode i need to save only the itemcode in database and need to retrive it and display itemname. for that i need the item code of the selected name. how to do so. 
> 
> thanks for ur reply


The code in post #1 already does exactly that.  Have you run the code?  The child table bound to the grid contains the ParentID yet the column displays the ParentName.  That's no different to your itemcode and itemname.

----------


## vpm_sampath

Sorry for disturbing u.
  It works good.
Thank u very much almost my 3 projects have been finished

Thanks.......! :wave: 
Thanks.......! :wave: 
Thanks.......! :wave: 
Thanks.......! :wave: 
Thanks.......! :wave: 
Thanks.......! :wave: 
Thanks.......! :wave:

----------


## vpm_sampath

Hi,

 I got that done. But if i need the displayed value what option should i use.
Thanks

----------


## jmcilhinney

> Hi,
> 
>  I got that done. But if i need the displayed value what option should i use.
> Thanks


I've never actually tried that myself, but I believe that the FormattedValue property will give you that value.

----------


## kotlet

Nice work

But i have one problem and dont know how to solve it. I already have appplication with a lot of combos and textboxes on form (32 rows, in each row 5 combos and 5 texboxes and lot of code behind). Problem is that curent app is very slow on form load. With your sample i could make it a lot faster.

Already have gridview filled with some test data.

And the problem is:

When i click on combobox in use this code to display dropdown (to click only once to display dropdown).



```
Private Sub DataGridView1_CellMouseClick(ByVal sender As Object, ByVal e As System.Windows.Forms.DataGridViewCellMouseEventArgs) Handles DataGridView1.CellMouseClick
        Try
            If e.RowIndex = -1 Then Exit Sub
            Select Case e.ColumnIndex
                Case 0, 2, 4, 6, 8
                    DataGridView1.BeginEdit(True)

                    Dim controll As DataGridViewComboBoxEditingControl = DataGridView1.EditingControl
                    If controll IsNot Nothing Then
                        controll.DroppedDown = True

                    End If

            End Select
        Catch ex As Exception
            MsgBox(ex.Message & "  " & e.RowIndex & "  " & e.ColumnIndex)
        End Try

    End Sub

    Private Sub gwKupuje_DataError(ByVal sender As Object, ByVal e As System.Windows.Forms.DataGridViewDataErrorEventArgs) Handles DataGridView1.DataError
        If e.Context = DataGridViewDataErrorContexts.Formatting _
               Or e.Context = DataGridViewDataErrorContexts.PreferredSize Then
            e.ThrowException = False
        End If
    End Sub
```

When i click on item in dropdown the cell is filled with selected text. But CellValueChanged event is fired when i go out from cel in clicked on other cell. Now how i set that value is changed when i click on item in dropdown, or to catch this event?

I need this for enable or disable (ready only) next cell in gridview.

An one more thing.

I want to add one column in gridview like row number, starting with 0.

----------


## jmcilhinney

> Nice work
> 
> But i have one problem and dont know how to solve it. I already have appplication with a lot of combos and textboxes on form (32 rows, in each row 5 combos and 5 texboxes and lot of code behind). Problem is that curent app is very slow on form load. With your sample i could make it a lot faster.
> 
> Already have gridview filled with some test data.
> 
> And the problem is:
> 
> When i click on combobox in use this code to display dropdown (to click only once to display dropdown).
> ...


What you think you need, you don't need.  First up, you don't need any code to make the combo boxes drop down with a single click.  You simply set the EditMode property to EditOnEnter.

As for the cell value changing, whether it changes as soon as the user makes a selection or when they navigate away is irrelevant.  To navigate to another cell they must navigate away from the current cell, so the CellValueChanged event will be raised and you can configure the other cells in the row regardless.  Here's an update to the code from the first post in this thread:

```
Private Sub Form1_Load(ByVal sender As Object, _
                       ByVal e As EventArgs) Handles MyBase.Load
    Me.BindingSource2.DataSource = Me.GetParentTable()
    Me.Column1.DisplayMember = "ParentName"
    Me.Column1.ValueMember = "ParentID"
    Me.Column1.DataSource = Me.BindingSource2

    Me.BindingSource1.DataSource = Me.GetChildTable()
    Me.DataGridView1.DataSource = Me.BindingSource1
End Sub

Private Function GetParentTable() As DataTable
    Dim table As New DataTable

    With table.Columns
        .Add("ParentID", GetType(Integer))
        .Add("ParentName", GetType(String))
    End With

    With table.Rows
        .Add(1, "Parent 1")
        .Add(2, "Parent 2")
        .Add(3, "Parent 3")
    End With

    Return table
End Function

Private Function GetChildTable() As DataTable
    Dim table As New DataTable

    With table.Columns
        .Add("ChildID", GetType(Integer))
        .Add("ParentID", GetType(Integer))
        .Add("ChildName", GetType(String))
    End With

    With table.Rows
        .Add(1, 3, "Child 1")
        .Add(2, 2, "Child 2")
        .Add(3, 1, "Child 3")
    End With

    Return table
End Function

Private Sub DataGridView1_CellValueChanged(ByVal sender As Object, _
                                           ByVal e As DataGridViewCellEventArgs) Handles DataGridView1.CellValueChanged
    Dim row = e.RowIndex
    Dim column = e.ColumnIndex

    If column = 1 Then
        If CInt(Me.DataGridView1(column, row).Value) = 2 Then
            Me.DataGridView1(0, row).ReadOnly = True
            Me.DataGridView1(2, row).ReadOnly = True
        Else
            Me.DataGridView1(0, row).ReadOnly = False
            Me.DataGridView1(2, row).ReadOnly = False
        End If
    End If
End Sub
```

Also, set the EditMode of the grid in the designer.  Now, try running that code and editing the values in the first column.  You'll find that the combo boxes drop down on the first click, assuming that you click the drop-down arrow and not the text area.  Also note that, if you select 'Parent 2', the rest of the cells in the row become read-only while, if you select a different parent, the other cells are editable.

----------


## kotlet

> What you think you need, you don't need.  First up, you don't need any code to make the combo boxes drop down with a single click.  You simply set the EditMode property to EditOnEnter.
> 
> As for the cell value changing, whether it changes as soon as the user makes a selection or when they navigate away is irrelevant.  To navigate to another cell they must navigate away from the current cell, so the CellValueChanged event will be raised and you can configure the other cells in the row regardless.


Actualy in need.

When user change some values in gridview, and dont navigate back from last field, which was edited, he must press button under gridview to confirm changes. So last edited field keeps old value.

----------


## jmcilhinney

> Actualy in need.
> 
> When user change some values in gridview, and dont navigate back from last field, which was edited, he must press button under gridview to confirm changes. So last edited field keeps old value.


All that means is that you're not calling EndEdit before saving.  Call EndEdit and that will force any pending changes to be committed.

----------


## kotlet

Is iz possible to have different comboboxes in same column?

If i have one row with 2 comboboxes.

When i change value in first combobox i want to change items in second combobox (i want to get data from database).

In next row i again change data in first combo and i want to get diferent data in second combo.

----------


## bodylojohn

Hello JMC,

Why use Me.BindingSource2.DataSource = Me.GetParentTable()
when you also can use Me.Column1.DataSource = GetParentTable()  

Or is there a specific reason why you use the bindingsource?

----------


## jmcilhinney

BindingSources provide a single point of contact for bound data.  They don't provide anything that can't be done another way but they do make various things easier.  I tend to use a BindingSource every time I bind data.

----------


## bodylojohn

JMC..

Thank you for your explenation. I still learn a lot from you.

----------


## naviruishen

I have a question sir. 

Here is my database query :



```
dim dt as Datatable
dt = "Select Status FROM Employee"
```

Status can only be Married or Single.

Is it possible for my comboboxes in datagridviewcomboboxcolumn to display different datasource?

Here is my idea.



```
Dim bs1,bs2 as New BindingSource
Dim tb1,tb2 as new DataTable

tb1 = "Select Lastname From Employee"
tb2= "Select Age From Employee"

bs1.Datasource = tb1
bs2.Datasource = tb2
```

Now to bind data to the combobox depending on what the Status is.



```
Dim count as integer
count =dt.Rows.Count 

For i = 0 to count - 1

If status = single then
combobox.Datasource = bs1
Else
combobox.Datasource = bs2
End if

Next
```

Im wondering if this idea is possible? Thank you Sir!

----------


## coolwater

Thank you very much for sharing this solution. I've been looking for a simple solution and you nailed it.

----------


## bodylojohn

Dear JMC,

I almost got everything to work except:
When I select a value form the combobox "column1" the valuemember isn't shown in the column "Wagen_ID" of my childtable (GetDataRit). See code below.
Probably I have done something wrong but I just can see what it is.
I hope you can push me in the right direction.

Thanks.....






```
Imports System
Imports System.Data
Imports System.Data.OleDb

Public Class test
  Private bindingSource1 As New BindingSource()
  Private bindingSource2 As New BindingSource()
  Private dataAdapter1 As New OleDbDataAdapter()
  Private dataAdapter2 As New OleDbDataAdapter()

  Private Sub test_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
    GetDataTruck()
    Me.Column1.DisplayMember = "Kenteken"
    Me.Column1.ValueMember = "Wagen_ID"
    Me.Column1.DataSource = Me.bindingSource2

    GetDataRit()
    Me.DataGridView1.DataSource = Me.bindingSource1
    Me.DataGridView1.AllowUserToAddRows = False
  End Sub

  Private Sub GetDataRit()
    Dim sql As String = String.Format("SELECT	Datum,Chauffeur_ID,Wagen_ID,Beginstand,Eindstand,Liter,Dieselkoeling,Stops,StopsDachser,BrutoUren,Maut,Eurovignet FROM tblRIT")
    Me.dataAdapter1 = New OleDbDataAdapter(sql, _Connectionstring)
    Dim commandBuilder As New OleDbCommandBuilder(Me.dataAdapter1)
    Dim table As New DataTable()
    table.Locale = System.Globalization.CultureInfo.InvariantCulture
    Me.dataAdapter1.Fill(table)
    Me.bindingSource1.DataSource = table
  End Sub

  Private Sub btnUpdate_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnUpdate.Click
    Me.dataAdapter1.Update(CType(Me.bindingSource1.DataSource, DataTable))
    Me.DataGridView1.AllowUserToAddRows = False
  End Sub

  Private Sub btnDelete_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnDelete.Click
    If MessageBox.Show("Wilt u deze rij verwijderen ?", "Verwijder", MessageBoxButtons.YesNo) = DialogResult.Yes Then
      If Not DataGridView1.Rows(DataGridView1.SelectedCells(0).RowIndex).IsNewRow Then
        DataGridView1.Rows.RemoveAt(DataGridView1.SelectedCells(0).RowIndex)
        Me.dataAdapter1.Update(CType(Me.bindingSource1.DataSource, DataTable))
      End If
    End If
  End Sub

  Private Sub btnInsert_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnInsert.Click
    Me.DataGridView1.AllowUserToAddRows = True
  End Sub

  Private Sub GetDataTruck()
    Dim sql As String = String.Format("SELECT Wagen_ID, Kenteken from tblWAGEN")
    Me.dataAdapter2 = New OleDbDataAdapter(sql, _Connectionstring)
    Dim commandBuilder As New OleDbCommandBuilder(Me.dataAdapter2)
    Dim table As New DataTable()
    table.Locale = System.Globalization.CultureInfo.InvariantCulture
    Me.dataAdapter2.Fill(table)
    Me.bindingSource2.DataSource = table
  End Sub
End Class
```

----------


## jmcilhinney

> Dear JMC,
> 
> I almost got everything to work except:
> When I select a value form the combobox "column1" the valuemember isn't shown in the column "Wagen_ID" of my childtable (GetDataRit). See code below.
> Probably I have done something wrong but I just can see what it is.
> I hope you can push me in the right direction.
> 
> Thanks.....
> 
> ...


Did you set the DataPropertyName of the combo box column?

----------


## bodylojohn

That's the one thing I forgot to check.

Everything works like a charm!!!!

Thank you very much.

----------


## Grand

Hi,
In my case the datagridviews (DGV) are added at run time and contain a column with some value in it and sometimes no value. The idea is to give users possibilities to change and/or select two different values and then save (the content will be saved on a SQL database: out of scope). 
Do I need to add a column and bind a column of my table (the column of interest) to it and then add that column to my datagridview, or replace it with the column of interest? I also made then “readonly”; I guess I need to make that column editable too? Am I overcomplication things?

How exactly can I do that?  

This is how I add my DGVs:



```
'add new datagrid
            Dim MyGroupGrid As New DataGridView
            MyGroupGrid.Name = "DGV_" & MyTabPageName
            EnableDoubleBuffered(MyGroupGrid)
            With MyGroupGrid
                .Dock = DockStyle.Fill
                .RowHeadersVisible = False
                .ReadOnly = True
                .AllowUserToAddRows = False
                .AllowUserToResizeColumns = False
                .AllowUserToResizeRows = False
                .DataSource = TempTable
                .ClearSelection()
            End With
            ThisTab.Controls.Add(MyGroupGrid)
```

How will I add/replace that column with combobox? Shall I change the type from textbox to combobox? I guess I can’t once the column is created. I am a bit lost ☹

Edit:
Feel less lost:


```

            Dim CCB As New DataGridViewComboBoxColumn()
            With CCB
                .HeaderText = "IntOrExt"
                .Name = "Combo box name"
                .DataSource = TempTable
                .DataPropertyName = "IntOrExt"
                .DisplayMember = "IntOrExt"
                .ValueMember = "IntOrExt"
            End With

            DGV_MyGroupGrid.Columns.Add(CCB)
```

However, each combobox contains the entire column adn takes a lots of time to open the dropdown:

----------


## Chrissy

Thank you for the wonderful explanation!  Everything worked like charm except I don't know how to update my database from the selection in the drop down.  

I am loading information into the datagridview and want the combobox to populate based on what is already saved, and also allow user to select a new option.  How do I commit the change made from the drop down?  I feel like the answer is obvious... sorry if it is!  I am new to VB.NET... most of my experience is with VB.6... trying to move into the future.   :Smilie: 


Code Code:
Dim SQL As New SQLControl
    Private Sub Form1_Load(ByVal sender As Object,
                       ByVal e As EventArgs) Handles MyBase.Load
        Me.BindingSource2.DataSource = Me.GetParentTable()
        Me.Column1.DisplayMember = "List_Item"
        Me.Column1.ValueMember = "Data_code"
        Me.Column1.DataSource = Me.BindingSource2
         Me.BindingSource1.DataSource = Me.GetChildTable()
        Me.DataGridView1.DataSource = Me.BindingSource1
    End Sub
     Private Function GetParentTable() As DataTable
        Dim table As New SQLControl
         table.ExecQuery("SELECT * from dropdownlist WHERE  list_name = 'Renewal'")
         Return table.DBDT
     End Function
     Private Function GetChildTable() As DataTable
         SQL.AddParam("@prophmy", 637)
        SQL.AddParam("@budgetid", globalBudgetID)
         SQL.ExecQuery("SELECT Amendment_Type Amendment, Amendment_Status Status,  Units, Lease_Type 'Lease Type', Commence_Date 'Begin Date', Expiration_date 'End Date', Leased_sf 'Leased SF', lease_hmy, tenant_hmy, prop_hmy, budget_id, renewal_type " _
                      + " FROM lease WHERE budget_id = @budgetid  And prop_hmy = @prophmy ORDER BY sequence")
         Return SQL.DBDT
    End Function

----------


## jmcilhinney

> Thank you for the wonderful explanation!  Everything worked like charm except I don't know how to update my database from the selection in the drop down.  
> 
> I am loading information into the datagridview and want the combobox to populate based on what is already saved, and also allow user to select a new option.  How do I commit the change made from the drop down?  I feel like the answer is obvious... sorry if it is!  I am new to VB.NET... most of my experience is with VB.6... trying to move into the future.


Assuming that you have set up the bindings correctly, which you appear to have done, the fact that you're using a combo box column makes absolutely no difference to saving the data. You simply use a data adapter to save the changes from the DataTable bound to the grid with a call to Update, same as you always do. I'll try to explain the process in a bit more detail.

Let's say that you have a Parent table with ParentId (PK) and ParentName columns and a Child table with ChildId (PK), ParentId (FK) and ChildName columns. If you just query the Child table, populate a Datatable and bind that to a DataGridView then you'll see the numeric foreign key values in the ParentId column. If you use a combo box column instead, bind a DataTable populated from the Parent table and set DisplayMember and ValueMember to ParentName and ParentId respectively, the Value of each cell will still be the numeric ParentId value from the Child table but the cell will display the corresponding value from the ParentName column of the Parent column instead. If the user selects a different ParentName value from the drop-down list, it's still the corresponding ParentId value that gets pushed to the Value property of the cell so it's that foreign key value that gets pushed to the underlying DataTable. That means that you just save the DataTable as is and everything works as expected.

----------


## Chrissy

> Assuming that you have set up the bindings correctly, which you appear to have done, the fact that you're using a combo box column makes absolutely no difference to saving the data. You simply use a data adapter to save the changes from the DataTable bound to the grid with a call to Update, same as you always do. I'll try to explain the process in a bit more detail.
> 
> Let's say that you have a Parent table with ParentId (PK) and ParentName columns and a Child table with ChildId (PK), ParentId (FK) and ChildName columns. If you just query the Child table, populate a Datatable and bind that to a DataGridView then you'll see the numeric foreign key values in the ParentId column. If you use a combo box column instead, bind a DataTable populated from the Parent table and set DisplayMember and ValueMember to ParentName and ParentId respectively, the Value of each cell will still be the numeric ParentId value from the Child table but the cell will display the corresponding value from the ParentName column of the Parent column instead. If the user selects a different ParentName value from the drop-down list, it's still the corresponding ParentId value that gets pushed to the Value property of the cell so it's that foreign key value that gets pushed to the underlying DataTable. That means that you just save the DataTable as is and everything works as expected.


I knew it was something easy!  Thank you so much for your help.

----------

