vb.netindexofcase-insensitivedatagridviewcomboboxcell

Using IndexOf in ComboBoxCell.Items collection throws an exception in case-insensitive comparisons


I didn't find any good solution for my issue. A bit of explanations. I have DataGridView with a few Columns. In the first Column, the cell shows the path to some file. Starting from the third Column, I have couple of ComboBoxCells.

In the DropDown of the ComboBoxes, I wish to make auto-select equal (case insensitive) values to the part of the File path in the first cell. All this happens on Form.Load.
Later, users make their own choices.

Dim CmbCell As DataGridViewComboBoxCell = CType(DgvRow.Cells(2), DataGridViewComboBoxCell)
Dim ResultString As String
If HasDropDownThisValue(DgvRow.Cells(0).Value.ToString, CmbCell, ResultString) Then
    CmbCell.Value = CmbCell.Items(CmbCell.Items.IndexOf(ResultString))
End If

This is the method used in the If statement:

Private Function HasDropDownThisValue(ByVal GivenValue As String, ByRef comboCeel As DataGridViewComboBoxCell, ByRef ReturnValue As String) As Boolean
    ReturnValue = ""
    Dim boolret As Boolean = False
    Dim comparestring As String
    Dim StringArr() As String = Split(GivenValue, CStr(Path.DirectorySeparatorChar), -1, VisualBasic.CompareMethod.Text)
    comparestring = StringArr(0)
    For i As Integer = 1 To UBound(StringArr)

        If comboCeel.Items.Cast(Of String).Contains(comparestring, StringComparer.OrdinalIgnoreCase) Then
            ReturnValue = comparestring
            boolret = True
            Exit For
        Else
            comparestring = String.Format("{0}{1}{2}", comparestring, Path.DirectorySeparatorChar, StringArr(i))
        End If
    Next
    Return boolret
End Function

The line:

CmbCell.Value = CmbCell.Items(CmbCell.Items.IndexOf(ResultString))

throws an exception when the case doesn't match. How to avoid that?
I probably can do something like: CmbCell.Value = ResultString, but I prefer to pre-define values in Items collection.

Maybe something like this is possible (used in a function):

comboCeel.Items.Cast(Of String).Contains(comparestring, StringComparer.OrdinalIgnoreCase)

Solution

  • Since you need a case-insensitive match, you can use IndexOf(), with the StringComparison option set to StringComparison.OrdinalIgnoreCase, to find a string value in the DataGridViewComboBoxCell.ObjectCollection (which represents a collection of strings, in this case).

    I suggest to set Dim ResultString As String = Nothing and not to reset it to String.Empty ("") in the HasDropDownThisValue method: if the method returns False, you then set [ComboBoxCell].Value = ResultString (which is Nothing), so the ComboBox selection is cleared.
    Otherwise, use IndexOf() to find a matching string in the collection. Still, if no match is found, the resulting value will be Nothing, so the ComboBox is cleared; otherwise set the value found:

    (local variables renamed to comply with standard naming conventions)

    Dim resultString As String = Nothing
    Dim cmbCell = CType(DgvRow.Cells(2), DataGridViewComboBoxCell)
    
    If HasDropDownThisValue(DgvRow.Cells(0).Value?.ToString(), cmbCell, resultString) Then
        resultString = cmbCell.Items.OfType(Of String).
            FirstOrDefault(Function(i) i.IndexOf(resultString, StringComparison.OrdinalIgnoreCase) >= 0)
    End If
    cmbCell.Value = resultString
    

    As you can see, passing resultString as reference becomes quite useless. You can change your method to return a String instead of a Boolean, since we need to use that string anyway (no matter whether HasDropDownThisValue finds a match or not).

    Also, you shouldn't pass the ComboBox Cell ByRef: this object is already a Reference Type, you should pass it ByVal (or don't specify the modifier, since ByVal is the default).