Я успешно сохранил выделение одной строки при сортировке столбцов в DataGridView
, но на этот раз я намерен отслеживать выбор нескольких строк при сортировке столбцов в DataGridView
. Я видел один пост на эту топи c со ссылкой на DataGrid
, но ответ был бесполезным.
Сначала я попытался просто сделать копию предыдущей выбранной коллекции строк, а затем сделать копию текущей выбранной коллекции строк. Однако это не сработало, потому что при сортировке столбца я заметил, что событие SelectionChanged
срабатывает дважды до того, как событие Sorted
срабатывает один раз.
Поэтому я разработал класс, который хранит три последовательных копии, и после сортировки следует просто повторно выбрать самую раннюю из 3 копий. Sub UpdateSelection
вызывается для события SelectionChanged
, а sub SelectPrevious
вызывается для события Sorted
.
Однако
Проблема заключается в следующем: приведенный ниже код Кажется, работает при выборе элементов. Результаты Debug.Print
возвращаются корректно при каждом выборе элемента. НО , как только я сортирую, все этих копий массива очищаются при первом SelectionChanged
событии. Я действительно не понимаю, как.
Если я не ошибаюсь, поскольку каждый массив является копией, он должен остаться неизменным, верно? Даже если он очищает m_CurrentRows
, он не должен очищать m_PreviousRows0, 1, 2
. Он должен отступать по одному за раз, так же, как и при выделении строк.
Что я ищу
Я либо ищу способ не иметь все предыдущие массивы выборок полностью удалены - это само по себе непонятно.
Или способ сохранить выборку после вызова Sort
, но до срабатывания Sorted
. Это не очевидно, и нет никакого способа предвидеть, когда пользователь может щелкнуть заголовок столбца. Кажется, что попытка отследить выделение каждый раз, когда что-то выбрано или отменено, не сработает, поэтому, если есть способ перехватить его (как указано ниже), это было бы еще лучше, но я бы нужно знать как.
NB - модуль с расширениями - если я пропустил, дайте мне знать, и я включу. Кроме того, при проверке я использую значение ячейки 2, поэтому убедитесь, что в наборе данных есть как минимум 3 столбца.
Class clsDataGridViewSelectedRowTracker
Private ReadOnly m_DataGridView As DataGridView
Private ReadOnly m_CurrentRows As List(Of DataGridViewRow)
Private m_PreviousRows0() As DataGridViewRow
Private m_PreviousRows1() As DataGridViewRow
Private m_PreviousRows2() As DataGridViewRow
''' <summary>
''' Create new instance of DataGridView Selected Row Tracker
''' </summary>
''' <param name="dataGridView">Instance of DataGridView - SelectionMode must be FullRowSelect</param>
Friend Sub New(ByRef dataGridView As DataGridView)
m_DataGridView = dataGridView
m_CurrentRows = New List(Of DataGridViewRow)
m_PreviousRows0 = {}
m_PreviousRows1 = {}
m_PreviousRows2 = {}
If Not m_DataGridView.SelectionMode = DataGridViewSelectionMode.FullRowSelect Then
m_DataGridView.SelectionMode=DataGridViewSelectionMode.FullRowSelect
End If
End Sub
''' <summary>
''' Updates selection tracker with current and previous selection values
''' </summary>
Friend Sub UpdateSelection()
'Debugging the current issue - displays all values each time an item is selected
If m_CurrentRows.Count > 0 AndAlso m_PreviousRows2.Length > 0 Then
Debug.Print("{0} - {1} - {2} - {3}", "C: " & m_CurrentRows(0).Value.Cell(2), "0: " & m_PreviousRows0(0).Value.Cell(2), "1: " & m_PreviousRows1(0).Value.Cell(2), "2: " & m_PreviousRows2(0).Value.Cell(2))
ElseIf m_CurrentRows.Count > 0 AndAlso m_PreviousRows1.Count > 0 Then
Debug.Print("{0} - {1} - {2} - {3}", "C: " & m_CurrentRows(0).Value.Cell(2), "0: " & m_PreviousRows0(0).Value.Cell(2), "1: " & m_PreviousRows1(0).Value.Cell(2), "2: ")
ElseIf m_CurrentRows.Count > 0 AndAlso m_PreviousRows0.Count > 0 Then
Debug.Print("{0} - {1} - {2} - {3}", "C: " & m_CurrentRows(0).Value.Cell(2), "0: " & m_PreviousRows0(0).Value.Cell(2), "1: ", "2: ")
ElseIf m_CurrentRows.Count > 0 Then
Debug.Print("{0} - {1} - {2} - {3}", "C: " & m_CurrentRows(0).Value.Cell(2), "0: ", "1: ", "2: ")
End If
'Back up current rows and previous 2 instances
If m_PreviousRows1 IsNot Nothing AndAlso m_PreviousRows1.Length > 0 Then
ReDim m_PreviousRows2(m_PreviousRows1.Length - 1)
Call m_PreviousRows1.CopyTo(m_PreviousRows2, 0)
End If
If m_PreviousRows0 IsNot Nothing AndAlso m_PreviousRows0.Length > 0 Then
ReDim m_PreviousRows1(m_PreviousRows0.Length - 1)
Call m_PreviousRows0.CopyTo(m_PreviousRows1, 0)
End If
If m_CurrentRows.Count > 0 Then
ReDim m_PreviousRows0(m_CurrentRows.Count - 1)
Call m_CurrentRows.CopyTo(m_PreviousRows0, 0)
End If
'Get currently selected rows, if any
Dim m_selectedRows As DataGridViewSelectedRowCollection = m_DataGridView.SelectedRows
'Clear list of current rows
Call m_CurrentRows.Clear()
'Add each selected item to list of currently selected rows
For Each EachSelectedRow As DataGridViewRow In m_selectedRows
Call m_CurrentRows.Add(EachSelectedRow)
Next
End Sub
''' <summary>
''' Attempts to select the previously selected rows
''' </summary>
Friend Sub SelectPrevious()
'Ensure Grid exists and contains rows
If m_DataGridView IsNot Nothing AndAlso m_DataGridView.RowCount > 0 Then
'Visible
Dim m_VisibleRow As DataGridViewRow = Nothing
'Compare each row value against previous row values
For Each EachDataGridViewRow As DataGridViewRow In m_DataGridView.Rows
'Use the level two instance of previous rows after sorting
For Each EachPreviousRow As DataGridViewRow In m_PreviousRows2
If EachPreviousRow.Value.Row.Equivalent(EachDataGridViewRow.Value.Row) Then
'Select the row
EachDataGridViewRow.Selected = True
'Only store visible row for the first selected row
If m_VisibleRow Is Nothing Then m_VisibleRow = EachDataGridViewRow
End If
Next 'Each Previous Selected Row
Next 'Each Row
'Ensure first selected row is always visible
If m_VisibleRow IsNot Nothing AndAlso Not m_VisibleRow.Displayed Then
If (m_VisibleRow.Index - m_DataGridView.DisplayedRowCount(True) \ 2) > 0 Then
'Place row in centre of DataGridView
m_DataGridView.FirstDisplayedScrollingRowIndex = m_VisibleRow.Index - m_DataGridView.DisplayedRowCount(True) \ 2
Else
'Place row at top of DataGridView
m_DataGridView.FirstDisplayedScrollingRowIndex = m_VisibleRow.Index
End If
End If
End If
End Sub
End Class
Module Extensions
''' <summary>
''' Determines whether the specified string is equivalent to current string (Not case sensitive)
''' </summary>
''' <param name="str1">The string to compare with the following string</param>
''' <param name="str2">The second string to compare</param>
''' <returns></returns>
<DebuggerStepThrough()>
<Extension()>
Friend Function Equivalent(ByVal str1 As String, str2 As String) As Boolean
Return str1.ToUpper.Equals(str2.ToUpper)
End Function
''' <summary>
''' Quick extension to speed up proceedings
''' </summary>
''' <param name="dgvr"></param>
''' <param name="cellindex"></param>
''' <returns></returns>
<Extension>
Friend Function CellValueString(ByRef dgvr As DataGridViewRow, ByVal cellindex As Integer) As String
If dgvr Is Nothing Then Return String.Empty
If dgvr.Cells Is Nothing Then Return String.Empty
If cellindex >= dgvr.Cells.Count Then Return String.Empty
If dgvr.Cells(cellindex).Value Is Nothing Then Return String.Empty
Return dgvr.Cells(cellindex).Value.ToString
End Function
End Module