Как заморозить объединенные столбцы в виде сетки данных при вертикальной прокрутке? - PullRequest
1 голос
/ 07 ноября 2019

У меня есть представление таблицы данных, где мне нужно, чтобы столбцы были заморожены или исправлены при вертикальной прокрутке.

У меня есть элемент управления видом таблицы данных в приложении Windows vb.net, которое отображает данные в родительскомдочерняя иерархия (как показано ниже). В первом столбце отображаются родительские данные, а во втором столбце отображаются все его дочерние данные. Дочерние данные во втором столбце могут содержать до 100 строк или даже больше. Таким образом, при прокрутке вниз по сетке значение в первом столбце не остается там, как есть, в то время как значения во втором столбце (т.е. дочерние данные) прокручиваются вниз. Таким образом, если пользователь хочет проверить, к какому родительскому элементу относится текущая информация о дочернем элементе, он снова должен будет прокрутить вверх до начала столбца, чтобы найти имя родительского элемента. Я хочу, чтобы значения в первом столбце отображались или фиксировались до тех пор, пока он не достигнет конца списка своих дочерних значений в сетке или, по крайней мере, до следующей строки, где начинаются следующие родительские данные. Я предложил клиенту перейти к древовидному представлению, но они не согласны и нуждаются в этом в самом представлении таблицы данных. Есть ли способ достичь этого в виде сетки данных? Заранее спасибо. enter image description here

1 Ответ

0 голосов
/ 08 ноября 2019

Вы не можете заморозить строку (во время выполнения, при прокрутке dgv) с индексом больше нуля, потому что все предыдущие версии заморожены, и в этот момент вы не можете прокрутить свое представление данных.

Если я правильно понял, что вы хотите, я написал этот класс быстро (вероятно, следует оптимизировать). Использование простое.

1 - Сначала создайте свое собственное представление данных.

2 - затем добавьте столбцы и строки (ВАЖНО: в каждой строке тега «X» указывается родительский элемент или он считается заголовком для других строк, как вы видели в методе TestPopulate).

3 - Вызовите класс, который я создал, передав в качестве параметра сетку данных (которую вы создали сначала). На этом этапе этот элемент управления получает свой размер, размещение и ЗАМЕНИТЕ СВОЮ ДАННУЮ СМЕТЬ.

  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

Использование:

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

Надеюсь, что помог мне

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...