【发布时间】:2020-07-01 13:17:01
【问题描述】:
在对DataGridView 中的列进行排序时,我成功地保留了单行的选择,但这次我打算在对DataGridView 中的列进行排序时跟踪多行的选择。我看到一篇关于这个主题的帖子提到了DataGrid,但答案没有帮助。
首先,我尝试非常简单地复制先前选定的行集合,然后复制当前选定的行集合。但是这不起作用,因为当您对列进行排序时,我注意到SelectionChanged 事件在Sorted 事件触发一次之前触发两次。
因此我设计了一个存储三个连续副本的类,在排序后,它应该重新选择三个副本中最早的一个。 UpdateSelection sub 在 SelectionChanged 事件上调用,SelectPrevious sub 在 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
【问题讨论】:
-
如果网格绑定到
BindingSource,那么行索引将对应于BindingSource中的项目索引。您可以在排序之前获取这些索引处的项目,然后在排序之后获取这些项目的新索引,然后选择这些索引处的行。 -
dgv.DataSource = 数据表。我不确定如何在“排序之前”获取索引,因为我不确定在
Sorted之前会触发什么以便获取此信息并在Sorted中使用它。我也不确定如何从数据表中获取项目的索引。 -
然后使用
BindingSource。 “调用排序后存储选择的方法”。为什么在拨打Sort之后还要这样做?为什么以前不这样做?
标签: vb.net datagridview columnsorting