Click here to Skip to main content
15,886,919 members
Please Sign up or sign in to vote.
1.00/5 (1 vote)
See more:
Hello,

Can anyone help me with the following?

I want to make sure that the value I enter, remains in a datagridviewcombobox?
The value I just entered is added to the list, but as soon as I select another cell, the value disappears.

What I have tried:

In the EditingControlShowing routine I change the dropdownstyle to dropdown, this gives the possibility to enter data in the combobox cell.

In the CelValidating routine I add the entered text and try to set the new value (comboBoxCell.Value = e.FormattedValue) but here is goes wrong. The text is added but the value disappears when selecting another cell.

Anyone an idea why this happens?

See my code below.

VB.NET

Private Sub DGV_Component_Invoer_EditingControlShowing(sender As Object, e As DataGridViewEditingControlShowingEventArgs) Handles DGV_Component_Invoer.EditingControlShowing

        Try

            If TypeOf e.Control Is DataGridViewComboBoxEditingControl Then
                CType(e.Control, ComboBox).DropDownStyle = ComboBoxStyle.DropDown
                'CType(e.Control, ComboBox).AutoCompleteSource = AutoCompleteSource.ListItems
                'CType(e.Control, ComboBox).AutoCompleteMode = System.Windows.Forms.AutoCompleteMode.Suggest
            End If

        Catch ex As Exception
            MsgBox(ex.Message)
        End Try

    End Sub

    Private Sub DGV_Component_Invoer_CellValidating(sender As Object, e As DataGridViewCellValidatingEventArgs) Handles DGV_Component_Invoer.CellValidating

        Try

            Dim comboBoxCell As DataGridViewComboBoxCell = CType(DGV_Component_Invoer.Rows(e.RowIndex).Cells(2), DataGridViewComboBoxCell)
            If (e.RowIndex = comboBoxCell.RowIndex) Then
                If (Not comboBoxCell.Items.Contains(e.FormattedValue)) Then
                    comboBoxCell.Items.Add(e.FormattedValue)
                    comboBoxCell.Value = e.FormattedValue
                End If
            End If

        Catch ex As Exception
            MsgBox(ex.Message)
        End Try

    End Sub



UPDATE

I tried a new approach without the CellValidate event as user 15627495 suggested.
Now I use the KeyDown Event, but unfortunately the result remains the same.
It's possible to add a new value to the list of colors but after tab or enter, the list is cleared, I want the ComboBox to show the new value.

See below the complete code in a test project

VB.NET

Public Class test

    Public Property Colors As List(Of String) = New List(Of String)() From
        {
        "Red",
        "Green",
        "Blue"
        }

    Public Sub New()
        InitializeComponent()
    End Sub

    Private Sub test_Load(sender As Object, e As EventArgs) Handles Me.Load

        Dim comboBoxColumn = New DataGridViewComboBoxColumn()
        Dim comboBoxCell = New DataGridViewComboBoxCell

        DataGridView1.Columns.Clear()
        DataGridView1.Columns.Add(comboBoxColumn)

        comboBoxCell = DataGridView1.Item(0, 0)
        comboBoxCell.Items.AddRange(Colors.ToArray)

    End Sub

    Private Sub DataGridView1_EditingControlShowing(sender As Object, e As DataGridViewEditingControlShowingEventArgs) Handles DataGridView1.EditingControlShowing


        RemoveHandler e.Control.PreviewKeyDown, AddressOf cBox_KeyDown

        If TypeOf e.Control Is DataGridViewComboBoxEditingControl Then
            CType(e.Control, ComboBox).DropDownStyle = ComboBoxStyle.DropDown
            CType(e.Control, ComboBox).AutoCompleteSource = AutoCompleteSource.ListItems
            CType(e.Control, ComboBox).AutoCompleteMode = System.Windows.Forms.AutoCompleteMode.Suggest
        End If

        AddHandler e.Control.PreviewKeyDown, AddressOf cBox_KeyDown

    End Sub

    Private Sub cBox_KeyDown(sender As Object, e As PreviewKeyDownEventArgs)
        Dim cBox As DataGridViewComboBoxEditingControl = sender
        Dim val As Object = cBox.Text

        If e.KeyCode = Keys.Tab Or e.KeyCode = Keys.Enter Then
            Dim cBoxCell As DataGridViewComboBoxCell

            cBoxCell = DataGridView1.CurrentCell
            cBoxCell.Items.Add(val)
            cBoxCell.Value = val

        End If
    End Sub

End Class
Posted
Updated 16-Jul-23 3:57am
v4
Comments
Member 15627495 14-Jul-23 16:48pm    
It's an error of 'events'.

'validating' is about componants draw and finishing their build.

in final thing to do, choose another event for your 2nd function
vincentkoert 15-Jul-23 11:39am    
You have any idea which event to choose?

1 solution

You don't mention if you are working on a WPF or WinForms app, nor do you mention if you are using .Net 3.0+ or .Net Framework 4.5+, so I will assume it is a .Net Framework 4.5 WinForms app. You're using VB.Net, so I will do the same.

You can let the DataGridView control do all of the work for you, you do not need to do this manually. Below is a sample app to demonstrate this.

1. Create a new "Windows Forms app (.Net FrameWork) in Visual Studio
2. Drop a DataGridView control on the design surface, click on the arrow button in the top-right corner, and select "Doct to Container"
3. now go to code view and add the following code:
VB.NET
Public Class Form1

    Public Property Widgets As List(Of Widget) = New List(Of Widget)()

    Public Property Colors As List(Of String) = New List(Of String)() From
        {
        "Red",
        "Green",
        "Blue"
        }

    Public Sub New()
        InitializeComponent()

        CreateWidgets()
        SetupDataGrid()
    End Sub

    Private Sub SetupDataGrid()
        DataGridView1.DataSource = Widgets
        DataGridView1.ColumnHeadersVisible = True
        DataGridView1.AutoGenerateColumns = False
        DataGridView1.EditMode = DataGridViewEditMode.EditOnKeystroke

        Dim NameColumn = New DataGridViewTextBoxColumn()
        NameColumn.HeaderText = "Name"
        NameColumn.ReadOnly = True
        NameColumn.DataPropertyName = "Name"

        Dim comboBoxColumn = New DataGridViewComboBoxColumn()
        comboBoxColumn.HeaderText = "Color"
        comboBoxColumn.DataSource = Colors
        comboBoxColumn.DataPropertyName = "Color"

        DataGridView1.Columns.Clear()
        DataGridView1.Columns.Add(NameColumn)
        DataGridView1.Columns.Add(comboBoxColumn)
    End Sub

    Private Sub CreateWidgets()
        Dim colorIndex As Integer = 0

        For i As Integer = 0 To 9
            Widgets.Add(New Widget() With {
                           .Name = $"Widget {i}",
                           .Color = Colors(colorIndex)
                           })

            colorIndex += 1

            If colorIndex = Colors.Count Then
                colorIndex = 0
            End If
        Next
    End Sub
End Class

Public Class Widget
    Public Property Name As String
    Public Property Color As String
End Class

Now run the app. You can change the values in the ComboBox in each column and the value selected remains.

The SetupDataGrid() subroutine manually configures the DataGridView control, first the Control, then each column.

UPDATE

That is a little different. For the DataGridViewTextBoxColumn, we cannot set the DataSource for the column as it is readonly. If you do use the DataSource for the column, then you will see the following unhandled exception in the OnCellValidating event when trying to update the column's Items collection:
System.ArgumentException: 'Items collection cannot be modified when the DataSource property is set.'
However, from what I have read, you can update it if we are using a DataTable.

So here is the above solution altered to support in-cell ComboBox editing.
VB.NET
Partial Public Class Form1
    Inherits Form
    Public Property Widgets As List(Of Widget) = New List(Of Widget)()

    Public Property Colors As List(Of String) = New List(Of String)() From {
        "Red",
        "Green",
        "Blue"
    }

    Public Sub New()
        InitializeComponent()
        CreateWidgets()
        SetupDataGrid()
    End Sub

    Private Sub SetupDataGrid()
        DataGridView1.DataSource = Widgets
        DataGridView1.ColumnHeadersVisible = True
        DataGridView1.AutoGenerateColumns = False
        DataGridView1.EditMode = DataGridViewEditMode.EditOnKeystroke

        Dim NameColumn = New DataGridViewTextBoxColumn()
        NameColumn.HeaderText = "Name"
        NameColumn.ReadOnly = True
        NameColumn.DataPropertyName = "Name"

        Dim comboBoxColumn = New DataGridViewComboBoxColumn()
        comboBoxColumn.HeaderText = "Color"

        ' Can not use DataSource for in-cell new ComboBox values
        ' comboBoxColumn.DataSource = Colors
        For Each color As String In Colors
            comboBoxColumn.Items.Add(color)
        Next

        comboBoxColumn.DataPropertyName = NameOf(Widget.Color)

        DataGridView1.Columns.Clear()
        DataGridView1.Columns.Add(NameColumn)
        DataGridView1.Columns.Add(comboBoxColumn)

        AddHandler DataGridView1.CellValidating, AddressOf OnCellValidating
        AddHandler DataGridView1.EditingControlShowing, AddressOf OnEditingControlShowing
    End Sub

    Private Sub CreateWidgets()
        Dim colorIndex As Integer = 0

        For i As Integer = 0 To 9
            Widgets.Add(New Widget() With {
                .Name = $"Widget {i}",
                .Color = Colors(colorIndex)
            })

            colorIndex += 1

            If colorIndex = Colors.Count Then
                colorIndex = 0
            End If
        Next
    End Sub

    Private Sub OnEditingControlShowing(sender As Object, e As DataGridViewEditingControlShowingEventArgs)
        ' column
        Dim column = TryCast(DataGridView1.Columns(1), DataGridViewComboBoxColumn)

        ' cell column
        Dim cellIndex As Integer = DataGridView1.CurrentCellAddress.X

        ' column type
        Dim type As Type = e.Control.GetType()

        If cellIndex <> column.DisplayIndex OrElse type <> GetType(DataGridViewComboBoxEditingControl) Then
            Return
        End If

        ' allow combobox editing
        Dim cb As ComboBox = TryCast(e.Control, ComboBox)

        If cb IsNot Nothing Then
            cb.DropDownStyle = ComboBoxStyle.DropDown
        End If
    End Sub

    Private Sub OnCellValidating(sender As Object, e As DataGridViewCellValidatingEventArgs)
        ' column
        Dim column = TryCast(DataGridView1.Columns(1), DataGridViewComboBoxColumn)

        ' cell column
        Dim cellIndex As Integer = DataGridView1.CurrentCellAddress.X

        ' add if new
        If cellIndex <> column.DisplayIndex Then
            Return
        End If

        Dim color As String = If(TryCast(e.FormattedValue, String), String.Empty)

        If String.IsNullOrWhiteSpace(color) OrElse Colors.Contains(color) Then
            Return
        End If

        Colors.Add(color)
        column.Items.Add(e.FormattedValue)

        ' set the new value to the cell
        DataGridView1.CurrentCell.Value = e.FormattedValue
    End Sub
End Class

Public Class Widget
    Public Property Name As String
    Public Property Color As String
End Class

The code will work (tested) in both .Net Framework or Dot Net Core.
 
Share this answer
 
v4
Comments
vincentkoert 15-Jul-23 11:01am    
Hi Graeme_Grand,

Thanks for your input. It's indeed a WindowsForms app in .NET6.0

I want the user to be able to add values to the list. For instance the list has Green, Blue and Red and they can add Black. In my code this is possible but if they add Black and select another box, the combobox goes blank and you have to select it again to get the just added value.
Im sorry, but it's difficult for me to explain in English, I hope you understand what i mean.
Graeme_Grant 15-Jul-23 19:13pm    
I updated my answer.
vincentkoert 16-Jul-23 10:09am    
Hi Greame_Grand,
I have removed my aswer and updated my original question like you told.
I just tried your code but sadly it does the same as mine. It add's the new value to the list but doesn't set the new value to the cell, it just goes blank after enter or tab. Am I missing something?
Graeme_Grant 16-Jul-23 10:41am    
Actually, it works as requested. I did run and test the code used in the update. Not sure what you are doing. Follow my instructions in the first part to create a test project and use the updated code.
Graeme_Grant 16-Jul-23 11:35am    
Glad to hear that you got it working.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900