首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何在垂直滚动时冻结数据网格视图中的合并列?

如何在垂直滚动时冻结数据网格视图中的合并列?
EN

Stack Overflow用户
提问于 2019-11-07 17:45:14
回答 1查看 340关注 0票数 1

我有一个数据网格视图,我需要在垂直滚动时冻结或固定列。

我在vb.net windows应用程序中有一个数据网格视图控件,它以父子层次结构显示数据(如下所示)。第一列显示父数据,第二列显示其所有子数据。第二列中的子数据可以多达100行,甚至更多。因此,当在网格中向下滚动时,第一列中的值不会保持原样,而第二列中的值(即子数据)向下滚动。因此,如果用户想要检查当前的孩子信息属于哪个父母,那么他将不得不再次向上滚动到列的开头来查找父母的名字。我希望第一列中的值被显示或冻结,直到它到达网格中它的子值列表的末尾,或者至少到下一个父数据开始的下一行。我曾建议客户使用树视图,但他们不同意,需要在数据网格视图中使用树视图。有没有办法在数据网格视图中实现这一点?提前谢谢。

EN

回答 1

Stack Overflow用户

发布于 2019-11-08 05:50:12

您不能冻结索引大于零的行(在运行时,在dgv滚动时),因为之前的所有行都已冻结,此时您无法滚动datagridview。

如果我没弄错你想要什么,我很快就写了这个类(可能应该优化一下)。使用方法很简单。

1-首先创建你自己的datagridview。

2-然后添加你的列和行(重要的:在每一行的标签中放一个“X”是父级的,或者被认为是其他行的标题,就像你在TestPopulate方法中看到的那样)。

3-通过将datagridview (您首先创建的)作为参数传递来调用我创建的类。此时,此控件采用其大小、位置并替换您的DATAGRIDVIEW。

代码语言:javascript
运行
复制
  Private Class CustomDgv
    Inherits Panel

    Dim WithEvents TopDgv As DataGridView = New DataGridView
    Dim WithEvents DownDgv As DataGridView = New DataGridView

    Dim Cols As Integer

    ' This variable is in case you have more rows as "headrow"
    ' In TestPopulate you can see how to get those
    Dim listOfOwnerRows As List(Of Integer) = New List(Of Integer)

    Dim currentTopRow As Integer = -1

    Protected Overloads Property Height As Integer
        Get
            Return MyBase.Height
        End Get
        Set(value As Integer)
            MyBase.Height = value
            TopDgv.Height = TopDgv.RowTemplate.Height - 1
            DownDgv.Height = value - TopDgv.Height - 1
        End Set
    End Property


    Protected Overloads Property Width As Integer
        Get
            Return MyBase.Width
        End Get
        Set(value As Integer)
            MyBase.Width = value
            TopDgv.Width = value - 1
            DownDgv.Width = value - 1
        End Set
    End Property


    Sub New(dgvOriginal As DataGridView)

        DownDgv = dgvOriginal

        Dim parentCtrl As Control = dgvOriginal.Parent
        parentCtrl.Controls.Remove(dgvOriginal)
        parentCtrl.Controls.Add(Me)

        Me.Location = DownDgv.Location
        Me.Size = DownDgv.Size
        Me.BorderStyle = DownDgv.BorderStyle

        TopDgv.Width = Width - 2 - SystemInformation.VerticalScrollBarWidth
        TopDgv.Height = TopDgv.RowTemplate.Height
        TopDgv.ScrollBars = ScrollBars.None
        TopDgv.ColumnHeadersVisible = False
        TopDgv.BorderStyle = BorderStyle.None

        DownDgv.ColumnHeadersVisible = False
        DownDgv.BorderStyle = BorderStyle.None

        TopDgv.Left = 0
        DownDgv.Left = 0
        DownDgv.Width = Width - 2
        DownDgv.Height = Height - 2

        For Each Col As DataGridViewColumn In DownDgv.Columns
            Dim cIndex As Integer = TopDgv.Columns.Add(Col.Clone)
            If Col.Frozen Then
                TopDgv.Columns(cIndex).Frozen = True
            End If
            Cols += 1
        Next

        DownDgv.Top = 0

        Me.Controls.Add(TopDgv)
        Me.Controls.Add(DownDgv)


        If DownDgv.Rows.Count > 0 Then

            listOfOwnerRows = (From R As DataGridViewRow In DownDgv.Rows
                               Where R.Tag = "X"
                               Select R.Index).ToList


            If listOfOwnerRows.Count > 0 Then
                SetFrosenRow(listOfOwnerRows(0))
            End If

        End If

    End Sub



    Protected Sub SetFrosenRow(index As Integer)

        If DownDgv.Rows.Count > index Then

            TopDgv.Rows.Clear()
            TopDgv.Rows.Add()

            Dim currentRIndex As Integer = DownDgv.FirstDisplayedScrollingRowIndex

            'If you want onlly the base row
            For i As Integer = 0 To Cols - 1
                TopDgv.Rows(0).Cells(i).Value = DownDgv.Rows(index).Cells(i).Value
            Next

            'Or else get the diplayed on top row 
            TopDgv.Rows(0).DefaultCellStyle = New DataGridViewCellStyle With {
            .BackColor = Color.Bisque
            }

            currentTopRow = index

        End If

    End Sub


    Protected Sub SetChildValuesInTopRow(index As Integer)
        For i As Integer = 1 To Cols - 1
            TopDgv.Rows(0).Cells(i).Value = DownDgv.Rows(index).Cells(i).Value
        Next
    End Sub


    Private Sub DownDgv_Scroll(sender As Object, e As ScrollEventArgs) Handles DownDgv.Scroll

        Try

            If e.ScrollOrientation = ScrollOrientation.VerticalScroll Then

                Dim topR As Integer = DownDgv.FirstDisplayedScrollingRowIndex

                'If you want in top row the current value that is in the top uncomment this 
                SetChildValuesInTopRow(topR)

                If listOfOwnerRows.Count > 0 Then

                    Dim rToSetAsOwner As Integer = listOfOwnerRows(listOfOwnerRows.Count - 1)
                    For i As Integer = listOfOwnerRows.Count - 1 To 0 Step -1
                        If listOfOwnerRows(i) <= topR Then
                            rToSetAsOwner = listOfOwnerRows(i)
                            Exit For
                        End If
                    Next

                    If rToSetAsOwner <> currentTopRow Then
                        SetFrosenRow(rToSetAsOwner)
                    End If

                    Console.WriteLine("rToSetAsOwner: " & rToSetAsOwner)

                End If

            Else

                TopDgv.HorizontalScrollingOffset = DownDgv.HorizontalScrollingOffset

            End If

        Catch ex As Exception
            Console.WriteLine(ex.ToString)
        End Try

    End Sub





End Class

用法:

代码语言:javascript
运行
复制
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles Me.Load
    Try

        ' first populate you grid putting a tag in each row which is a header/parent/title for other rows
        TestPopulate()

        Dim customControl As Control = New CustomDgv(DataGridView1)

    Catch ex As Exception
        Console.WriteLine(ex.ToString)
    End Try
End Sub



Sub TestPopulate()

    For i As Integer = 0 To 100

        DataGridView1.Rows.Add()

        If i = 0 Then
            DataGridView1.Rows.Item(0).Cells(0).Value = "Owner 0"
            DataGridView1.Rows(0).Tag = "X"
        End If


        If i = 50 Then
            DataGridView1.Rows.Item(50).Cells(0).Value = "Owner 50"
            DataGridView1.Rows(50).Tag = "X"
        End If


        If i = 70 Then
            DataGridView1.Rows.Item(70).Cells(0).Value = "Owner 70"
            DataGridView1.Rows(70).Tag = "X"
        End If


        DataGridView1.Rows.Item(i).Cells(1).Value = "child_" & i.ToString & "_1"
        DataGridView1.Rows.Item(i).Cells(2).Value = "child_" & i.ToString & "_2"

    Next

End Sub

我希望我能帮上忙

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/58745943

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档