Free                     Store                    Support
MS Bug 357763: DataGridView Column.DataPropertyName is not case-sensitive
On July 25, 2018, we identified a major bug in Microsoft's Visual Studio 2015 developer platform, which has not been fixed since July 18, 2008 (link here).   Specifically, we identified and confirmed that the Column.DataPropertyName of Microsoft's DataGridView (DGV) control was case-insensitive when a DGV is linked to a DataTable(DT).   This means that, for example, columns in a DataGridView whose intended column names are "McCarthy" and "MCARTHY", will contain the same data because the DataGridView.Column.DataPropertyName is case-insensitive.  Worse yet, when sorting on one of these columns, whose transformed lower case column names are identical, both columns will sorted together at the same time.

The column name problem was fixed in all NXG LOGIC software on 25.07.18, and mathematically, behind the scenes, this bug never had an effect on NXG LOGIC software calculations (only column names) since we never use data directly from a DT or DGV.   However, we do want to treat with caution the notion that developers who are unaware of the bug could experience errors if they use data directly from a DGV that's linked to a DT.

Example code is provided below to replicate the bug's effect, as well as programmatically apply a fix using a dictionary. 

Revision: July 26, 2018


Notice that when the Checkbox is not checked and the DataGridView is filled with random numbers, all of the column show the same data, while the original data sent to the DataGridView are all different random numbers (see bottom DataGridView).  In addition, when sorting one column, all of the columns sort at the same time.    

The problem is that the intended case-different column names are not interpreted as being different, because the Column.PropertyName is not case-sensitive, so all of the variants used for the name Jane are seen as the same in lower case (jane).
To replicate the bug's effect, and use a fix (dictionary), follow the steps below:
When the Checkbox is checked, and the DataGridView is filled with random numbers, all of the column shows the correct original data that is linked from the Data Table.    
1. Create a new .NET Project (2015 or later) using Windows Forms
2. Add a Button1, Checkbox1, DataGridView1, and DataGridView2 control to Form1.
3. Paste the code below into Button1.
4. Run with and without the checkbox selected.
5. When the fix is not applied, try sorting any row in the top DGV, and you will notice that all of the columns sort at the same time.


       
'(Paste all code below into Button1)

        'Fill a 10x10 array with random uniform numbers (0,1,...9 x 0,1,...,9)
        Randomize(123456) ' set the seed for the RNG
        Dim dataarray(9, 9) As Double
        For i As Integer = 0 To 9
           
For j As Integer = 0 To 9
                dataarray(i, j) = Rnd()
           
Next
        Next

        Dim fieldnames() As String = {"jane", "Jane", "jAne", "jaNe", "janE", "JAne", "jANe", "jaNE", "JANe", "JANE"}

       
' Create a data table and fill it with the random numbers
        Dim dt As New DataTable
        dt.Clear()
        dt.Rows.Clear()
        dt.Columns.Clear()
       
For j As Integer = 0 To UBound(fieldnames)
            dt.Columns.Add(fieldnames(j),
GetType(String))
           
Do While dt.Rows.Count <= UBound(fieldnames)
               
Dim myRow As DataRow
                myRow = dt.NewRow()
                dt.Rows.Add(myRow)
           
Loop
            ' Add each item to the cells in the column.
            For i As Integer = 0 To UBound(fieldnames)
                dt.Rows(i)(j) = dataarray(i, j)
           
Next i
       
Next j

       
'The code below will fix the bug by adding an increasing number of trailing blanks on the column name if the lower case version of the column name is seen multiple times.
        If CheckBox1.Checked = True Then
            Dim dicColNames As New Dictionary(Of String, Integer)
           
For i As Integer = 0 To dt.Columns.Count - 1
               
If dicColNames.ContainsKey(dt.Columns(i).ColumnName.ToLower) = True Then
                    Dim origcolname As String = dt.Columns(i).ColumnName.ToLower
                   
For k As Integer = 0 To dicColNames(dt.Columns(i).ColumnName.ToLower)
                        dt.Columns(i).ColumnName &=
" "
                    Next
                    dicColNames(origcolname) += 1
               
End If
                If dicColNames.ContainsKey(dt.Columns(i).ColumnName.ToLower) = False Then
                    dicColNames.Add(dt.Columns(i).ColumnName.ToLower, 1)
               
End If
            Next i
       
End If

        'Set some properties of the DataGridView1 on the Form
        DataGridView1.AutoGenerateColumns = False
        DataGridView1.DataSource = dt
        DataGridView1.AutoSizeColumnsMode =
DataGridViewAutoSizeColumnsMode.Fill
        DataGridView1.Columns.Clear()
       
'Fill the DGV with the data from the data table
        For i As Integer = 0 To dt.Columns.Count - 1
           
Dim Column As New DataGridViewTextBoxColumn
            Column.Name = dt.Columns(i).ColumnName
            Column.DataPropertyName = dt.Columns(i).ColumnName
            Column.HeaderText = dt.Columns(i).ColumnName
            Column.FillWeight = 70
            Column.MinimumWidth = 70
            DataGridView1.Columns.Add(Column)
       
Next i
        DataGridView1.Rows(0).Cells(0).Selected =
False

        'Create second data table (dt2) and fill with the same random numbers sent to data table 1 (dt)
        'Use column names that are simply 0,1,...,9, so that case-sensitive issues are not an issue
        Dim dt2 As New DataTable
        dt2.Clear()
        dt2.Rows.Clear()
        dt2.Columns.Clear()
       
For j As Integer = 0 To UBound(fieldnames)
            dt2.Columns.Add(j,
GetType(String))
           
Do While dt2.Rows.Count <= UBound(fieldnames)
               
Dim myRow As DataRow
                myRow = dt2.NewRow()
                dt2.Rows.Add(myRow)
           
Loop
            ' Add each item to the cells in the column.
            For i As Integer = 0 To UBound(fieldnames)
                dt2.Rows(i)(j) = dataarray(i, j)
           
Next i
       
Next j

       
'Set some properties of the DataGridView2 on the Form
        DataGridView2.AutoGenerateColumns = False
        DataGridView2.DataSource = dt2
        DataGridView2.AutoSizeColumnsMode =
DataGridViewAutoSizeColumnsMode.Fill
        DataGridView2.Columns.Clear()
       
'Fill the second DGV with the same random data
        For i As Integer = 0 To dt2.Columns.Count - 1
           
Dim Column As New DataGridViewTextBoxColumn
            Column.Name = i.ToString
            Column.DataPropertyName = i.ToString
            Column.HeaderText = i.ToString
            Column.FillWeight = 70
            Column.MinimumWidth = 70
            DataGridView2.Columns.Add(Column)
       
Next i
        DataGridView2.Rows(0).Cells(0).Selected =
False