【问题标题】:SortCompare Event not Firing for DataGridView Dynamically Added to TabControl动态添加到 TabControl 的 DataGridView 未触发 SortCompare 事件
【发布时间】:2025-12-01 00:45:01
【问题描述】:

使用数据表作为 datagridview 的数据源非常有效,但是,当对列进行排序时,我无法触发 Dgv_SortCompare 事件。主要问题是 dgv 值中(纯)数字列中的数值被排序为文本,例如1211.6小于89.7

In Button1:

Dim datagridview1 As New DataGridView
datagridview1.AutoSize = True
datagridview1.AutoResizeRows()
datagridview1.AutoResizeColumns()
datagridview1.ClearSelection()
DoubleBuffered(datagridview1, True)

datagridview1.AutoResizeRowHeadersWidth(DataGridViewRowHeadersWidthSizeMode.AutoSizeToAllHeaders)
Dim dgvColumnHeaderStyle As New DataGridViewCellStyle()
dgvColumnHeaderStyle.Alignment = DataGridViewContentAlignment.MiddleCenter
datagridview1.ColumnHeadersDefaultCellStyle = dgvColumnHeaderStyle
datagridview1.AllowUserToAddRows = False
datagridview1.ScrollBars = ScrollBars.Both
datagridview1.Dock = DockStyle.Fill

datagridview1.Refresh()
datagridview1.VirtualMode = False

Dim dgv As New DGVCREATE(datagridview1, dataarray, columnheaders, rowheaders, InputFeatureNames, InputObjectNames)

TabControl2.SelectedTab = TabControl2.TabPages.Item(0)
TabControl2.TabPages(0).Controls.Clear()
AddHandler() datagridview1.SortCompare, AddressOf dgv_SortCompare
TabControl2.TabPages(0).Controls.Add(datagridview1)
AddHandler CType(TabControl2.TabPages(0).Controls(0), DataGridView).SortCompare, AddressOf Me.dgv_SortCompare



Public Class DGVCREATE

    Sub New(ByRef dgv As DataGridView, ByVal dataarray(,) As Object, ByVal columnheaders() As String, ByVal rowheaders() As String, ByVal FieldNames() As String, ByVal RowNames() As String)

        dgv.RowHeadersWidthSizeMode = DataGridViewRowHeadersWidthSizeMode.DisableResizing

        ' Create the output table.
        GetResultsTable(rxdataarray, columnheaders, rowheaders, FieldNames, RowNames)

        'new trial code
        dgv.AutoGenerateColumns = False

        dgv.DataSource = Form1.MainDataTable
        dgv.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill

        'Set Column FillWeight in very large DGVs in order to prevent exception related to “Sum of FillWeight exceeds 65000”

        For i As Integer = 0 To Form1.MainDataTable.Columns.Count - 1
            Dim Column As New DataGridViewTextBoxColumn
            Column.Name = Form1.MainDataTable.Columns(i).ColumnName
            Column.DataPropertyName = Form1.MainDataTable.Columns(i).ColumnName
            Column.HeaderText = Form1.MainDataTable.Columns(i).ColumnName
            Column.FillWeight = 20
            Column.MinimumWidth = 20
            dgv.Columns.Add(Column)
        Next i

        For i As Integer = 0 To dgv.Columns.Count - 1
            If InputFeatureType(i + 1) = 1 Then
                dgv.Columns(i).ValueType = GetType(Int64)
                dgv.Columns(i).SortMode = DataGridViewColumnSortMode.Automatic
            End If
            If InputFeatureType(i + 1) = 2 Then
                dgv.Columns(i).ValueType = GetType(Double)
                dgv.Columns(i).SortMode = DataGridViewColumnSortMode.Automatic
            End If
            If InputFeatureType(i + 1) = 3 Then
                dgv.Columns(i).ValueType = GetType(Double)
                dgv.Columns(i).SortMode = DataGridViewColumnSortMode.Automatic
            End If
            If InputFeatureType(i + 1) = 4 Then
                dgv.Columns(i).ValueType = GetType(String)
                dgv.Columns(i).SortMode = DataGridViewColumnSortMode.Automatic
            End If
        Next i

        dgv.AutoSize = True
    End Sub

    Public Sub GetResultsTable(ByVal dataarray(,) As Object, ByVal columnheaders() As String, ByVal rowheaders() As String, ByVal fieldnames() As String, ByVal rownames() As String)
        Form1.MainDataTable.Clear()
        Form1.MainDataTable.Rows.Clear()
        Form1.MainDataTable.Columns.Clear()
        ' Loop through all process names.
        For j As Integer = 0 To UBound(columnheaders) - 1
            ' The current process name.
            ' Add the program name to our columns.
            Form1.MainDataTable.Columns.Add(fieldnames(j + 1))
            'Form1.MainDataTable.Columns.Add(fieldnames(j + 1))
            ' Keep adding rows until we have enough.
            Do While Form1.MainDataTable.Rows.Count < UBound(rowheaders)
                Form1.MainDataTable.Rows.Add()
            Loop
            ' Add each item to the cells in the column.
            For i As Integer = 0 To UBound(rowheaders) - 1
                Form1.MainDataTable.Rows(i)(j) = dataarray(i, j)
            Next i
        Next j
    End Sub
End Class

有什么建议吗?

【问题讨论】:

  • 无法复制 - DGV 中有什么需要帮助进行分类?
  • 数值被排序为字符串值,即1220.7被视为小于89.7。
  • 我怀疑原因是因为您正在向其中存储字符串。您不需要为每个单元格设置ValueType,只需dgv.Columns(n).ValueType = ... 设置整个列。我很确定您需要在添加任何数据之前执行此操作。 "D" 指定日期格式,请尝试“Nx”,其中 x 是位数。如果“D”格式包含数字的数字列,则应导致DataError。给定实际数字,默认排序应该可以正常工作。也许展示它是如何创建和填充的
  • 我添加了创建和填充的完整代码。
  • 你正在做很多你不需要的事情。 dataArray() 来自哪里?为什么数据需要在DataTable之前进入数组? As Object 几乎总是一个坏主意——它将真实类型装箱并隐藏它。由于您将 DGV 绑定到 DT,它将忽略指定的 DGV ValueType 并使用 DT 中的任何类型。由于这些都被装箱了,它使用ToString()。将正确键入的数据放入数据表中(如果需要,使用类对象 {Int64, Double Double, String} 作为 DTO)然后让 DGV 生成列,所有列都会按预期工作。

标签: vb.net sorting datagridview event-handling


【解决方案1】:

那里有很多不需要的代码。首先,您要避免将数据装箱As Object,因为它会阻止像 DGV 这样的东西看到它是什么类型。 DataTable 完全能够存储键入的数据。如果必须,您可以创建一个类来充当 DTO:

Public Class DataItem
    Public Property Able As Int64
    Public Property Baker As Double
    Public Property Charlie As Double
    Public Property Delta As String
End Class

由于DataTable 可以容纳多种类型,因此请使用它代替DataArray,并避免数据在此处跳跃:

Private dtData As DataTable
...
' create it somewhere
dtData = New DataTable
dtData.Columns.Add("Able", GetType(Int64))
dtData.Columns.Add("Baker", GetType(Double))
dtData.Columns.Add("Chanrlie", GetType(Double))   ' aka Charlie
dtData.Columns.Add("Delta", GetType(String))

用数据填充它:

For n As Int32 = 0 To 999
    dr = dtData.NewRow

    dr(0) = RNG.Next()        ' random value
    dr(1) = RNG.NextDouble()  ' random 0.00 to 1.0
    dr(2) = RNG.Next(-19, 20) + RNG.NextDouble()  ' -19.xx to +19.xx
    dr(3) = RD.GetNames(2, 35)  ' 2 random names
    ' add new row:
    dtData.Rows.Add(dr)
Next

填满后,让 DGV 为您创建列 - 它会从源中读取数据类型等:

dgv1.DataSource = dtData
For Each dc As DataGridViewColumn In dgv1.Columns
    Console.WriteLine(dc.ValueType)
Next

DGV 会看到这些类型并正确地对它们进行排序:

System.Int64
System.Double
System.Double
System.String

【讨论】:

  • 感谢 Plutonix!这太棒了。您是否正在使用 Mersenne Twister for RNGRNG.next() 看起来像 C# 在生成向量后对随机数的锐利使用。
  • 不,RNG 是标准的 NET Random 类,Next 是标准方法。 RD 是一个随机数据生成器,尽管用于名称(生成测试用的快速方法)。大多数 Mersenne 实现都继承自它,因此这些方法具有相同的名称。
最近更新 更多