【问题标题】:DataGridView Row Header number disappears when the Columns are sorted at runtime在运行时对列进行排序时,DataGridView 行标题编号消失
【发布时间】:2019-05-20 14:39:48
【问题描述】:

我有一个DataGridView 控件,我已将DataGridViewRow.HeaderCell.Value 设置为等于一个整数。这些行编号为1, 2, 3...(这可能无关紧要,无论我将值设置为什么,我都会遇到相同的行为)。

在运行时,当我单击列的标题来切换排序顺序时,行标题会消失。更准确地说,分配给标题的数值被清除。

我可以在 For Each 循环中轻松地将每个 DataGridViewColumn 的 SortMode 属性设置为 NotSortable,但我想保留排序功能。

有没有办法解决这个问题?

这是我的代码:

Imports System.IO
Imports System.Data.SqlClient

Public Class Form1

    Dim CMD As New SqlCommand()
    Dim ADP As New SqlDataAdapter()
    Dim TBL As New DataTable

    Dim serverStr As String = "Server"
    Dim databaseStr As String = "Database"
    Dim dbLoginStr As String = "Login"
    Dim dbPassStr As String = "Password"

    Dim qry As String

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click

        Dim connectionString As String =
            "Server=" & serverStr & ";" &
            "Database=" & databaseStr & ";" &
            "User Id=" & dbLoginStr & ";" &
            "Password=" & dbPassStr & ";" &
            "Timeout=1"

        qry = "SELECT * FROM INFORMATION_SCHEMA.TABLES ORDER BY TABLE_NAME ASC"

        Try
            Using SQL As New SqlConnection
                SQL.ConnectionString = connectionString

                CMD.Connection = SQL
                CMD.CommandText = qry
                ADP.SelectCommand = CMD

                SQL.Open()
                ADP.SelectCommand = CMD
                TBL.Clear()
                TBL.Columns.Clear()
                ADP.Fill(TBL)
                SQL.Close()
            End Using
        Catch ex As Exception
            MsgBox("Could not connect to " & databaseStr & " on server: " & serverStr & vbNewLine & vbNewLine & ex.Message)
            Exit Sub
        End Try

        DataGridView1.DataSource = TBL
        DataGridView1.AutoResizeColumns()
        SetRowNumber(DataGridView1)
        DataGridView1.Columns(DataGridView1.Columns.Count - 1).AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill
    End Sub

    Private Sub SetRowNumber(myDGV As DataGridView)
        For Each row As DataGridViewRow In myDGV.Rows
            row.HeaderCell.Value = (row.Index + 1).ToString()
        Next
        myDGV.AutoResizeRowHeadersWidth(DataGridViewRowHeadersWidthSizeMode.AutoSizeToAllHeaders)

        'Remove Sorting ability
        'For Each col As DataGridViewColumn In myDGV.Columns
        '    col.SortMode = DataGridViewColumnSortMode.NotSortable
        'Next
    End Sub

    'See if value got cleared upon sorting
    'Private Sub DataGridView1_ColumnHeaderMouseClick(sender As Object, e As DataGridViewCellMouseEventArgs) Handles DataGridView1.ColumnHeaderMouseClick

    '    Dim myDGV = DirectCast(sender, DataGridView)

    '    For Each row As DataGridViewRow In myDGV.Rows
    '        MsgBox(row.HeaderCell.Value)
    '    Next
    'End Sub
End Class

【问题讨论】:

    标签: vb.net winforms datagridview


    【解决方案1】:

    您可以使用RowPostPaint 事件在标题中绘制行号。
    每次需要重新绘制 Row 时都会引发此事件,因此每次需要重新绘制数字并将持续存在。

    您可能想要设置RowHeadersWidthSizeMode 属性:

    [DataGridView].RowHeadersWidthSizeMode = DataGridViewRowHeadersWidthSizeMode.DisableResizing
    

    这将防止用户调整行标题的大小,弄乱标题的标签(好吧,数字将被隐藏/部分可见。这仍然是一个选项)。

    数字是右对齐和垂直居中绘制的,因此数字将在左侧扩展。您可以更改此行为,将 StringFormat 的 StringAlignment 从 Far(右)更改为 Near(左):

     [StringFormat].Alignment = StringAlignment.Far   ' Align right
     [StringFormat].Alignment = StringAlignment.Near  ' Align left
    

    数字的颜色设置为 DataGridView 的 dgv.RowTemplate.DefaultCellStyle.ForeColor。
    更改此默认样式以设置不同的颜色。

    字体设置为 DataGridView 的 DefaultCellStyle.Font。同样的考虑。

    数字本身的格式为 $"{(e.RowIndex + 1):00}"。根据需要更改它。

    Private Sub DataGridView1_RowPostPaint(sender As Object, e As DataGridViewRowPostPaintEventArgs) Handles DataGridView1.RowPostPaint
        Dim dgv = DirectCast(sender, DataGridView)
        Dim rowHeader = $"{(e.RowIndex + 1):00}"
    
        Dim headerBounds As Rectangle =
            New Rectangle(e.RowBounds.Left, e.RowBounds.Top, dgv.RowHeadersWidth - 6, e.RowBounds.Height)
    
        Using format = New StringFormat(StringFormatFlags.NoWrap)
            format.Alignment = StringAlignment.Far
            format.LineAlignment = StringAlignment.Center
            Using brush As SolidBrush = New SolidBrush(dgv.RowTemplate.DefaultCellStyle.ForeColor)
                e.Graphics.DrawString(rowHeader, dgv.DefaultCellStyle.Font, brush, headerBounds, format)
            End Using
        End Using
    End Sub
    

    【讨论】:

    • 如您所见,这是一个事件处理程序。它处理DataGridView1.RowPostPaint 事件。您需要粘贴代码,然后使用设计器将此处理程序分配给事件。在事件列表中找到 DataGridView RowPaint 事件并分配此事件。删除/注释掉 SetRowNumber 方法。它会覆盖数字(起初)。
    • 我觉得我用错了这段代码,因为它看起来完全正确。我将它粘贴到我的项目中,但它似乎不起作用。该事件被配置为由 Sub 处理。对列进行排序仍然可以消除数字。如果我摆脱我的SetRowNumber 函数,那么根本不会出现任何行号。 Here's a video of what I'm experiencing with this pasted into my code
    • 是的,没错,阅读前面的评论。连接事件。不要忘记设置RowTemplate.DefaultCellStyle.ForeColor 和DefaultCellStyle.Font。它们通常没有设置。
    • 是的,这确实有效!在我看来,如果我对一个包含 'a-z' 的 26 行的列从升序到降序进行排序,我认为行号将保持 26 表示 'z' 和 1 表示 'a' 即使 z 现在位于顶部并且在视觉上第一排。我可以通过创建一个数组来存储查询时的初始行号来完成这项工作。非常感谢您提供的精彩代码!我真的没有做太多的绘画,所以这会让我很头疼。非常感谢您提供的所有信息以及为此付出的努力!
    猜你喜欢
    • 2012-12-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-10
    • 2012-08-09
    • 1970-01-01
    • 2011-01-02
    • 1970-01-01
    相关资源
    最近更新 更多