使用多选项向上或向下移动一些复杂的DataGridView行

我有一个像这样的DataGridView:

在此处输入图像描述

现在,在C#或者VB.Net中 ,有了一个按钮,我想向上或向下移动所选行的一个位置,我怎么能这样做? 多选的必要条件使我复杂化。

DataGridView中出现的文件将合并为一个可执行文件,然后,文件将按“ Order ”列的顺序执行,因此在向上或向下移动行时,“ Order ”值应该是不可变的。

我没有使用任何数据源。


我试图从MSDN分析这个示例,它包含一些扩展方法,但它需要一个数据表和数据源,我没有任何使用数据和数据源的失望但只是我不知道如何适应我的DataGridView的代码示例。 无论如何,样本不支持多选:

向上/向下移动行并记住DataGridView和ListBoxs数据绑定的顺序

我也在StackOverflow上看到了一些关于这个问题的C#问题,但他们要求选择单行:

如何在KeyUp或Keydown上按下向上/向下移动gridview所选行

DataGridView选定的行向上和向下移动

然后,我没有一个起点,只是这些方法移动一个也不保留Order值的SINGLE行,如果有人可以指导我扩展我的需求的function:Private Sub Button_MoveUp_Click(sender As Object,e作为EventArgs)_处理Button_MoveUp.Click

Me.MoveUpSelectedRows(Me.DataGridView_Files) End Sub Private Sub Button_MoveDown_Click(sender As Object, e As EventArgs) _ Handles Button_MoveDown.Click Me.MoveDownSelectedRows(Me.DataGridView_Files) End Sub Private Sub MoveUpSelectedRows(ByVal dgv As DataGridView) Dim curRowIndex As Integer = dgv.CurrentCell.RowIndex Dim newRowIndex As Integer = curRowIndex - 1 Dim curColIndex As Integer = dgv.CurrentCell.ColumnIndex Dim curRow As DataGridViewRow = dgv.CurrentRow If (dgv.SelectedCells.Count > 0) AndAlso (newRowIndex >= 0) Then With dgv .Rows.Remove(curRow) .Rows.Insert(newRowIndex, curRow) .CurrentCell = dgv(curColIndex, newRowIndex) End With End If End Sub Private Sub MoveDownSelectedRows(ByVal dgv As DataGridView) Dim curRowIndex As Integer = dgv.CurrentCell.RowIndex Dim newRowIndex As Integer = curRowIndex + 1 Dim curColIndex As Integer = dgv.CurrentCell.ColumnIndex Dim curRow As DataGridViewRow = dgv.CurrentRow If (dgv.SelectedCells.Count > 0) AndAlso (dgv.Rows.Count > newRowIndex) Then With dgv .Rows.Remove(curRow) .Rows.Insert(newRowIndex, curRow) .CurrentCell = dgv(curColIndex, newRowIndex) End With End If End Sub 

UPDATE

我正在尝试使用@Plutonix方法(稍加修改),唯一的问题是它没有将选定的行正确移动到UP方向。

重新定位问题的步骤:

  1. 选择两个在一起的行(例如,行索引2和行索引3,非行索引2和行索引4)

  2. 尝试将行向上移动。

我该怎么办呢?

 Public Enum MoveDirection As Integer Up = -1 Down = 1 End Enum Private Sub MoveRows(ByVal dgv As DataGridView, ByVal moveDirection As MoveDirection) Dim rows As DataGridViewRowCollection = dgv.Rows ' row index Dim thisRow As DataGridViewRow ' put selection back Dim selectedRows As New List(Of Integer) ' max rows Dim lastRowIndex As Integer = If(dgv.AllowUserToAddRows, rows.Count - 2, rows.Count - 1) For n As Integer = lastRowIndex To 0 Step -1 If Not rows(n).IsNewRow Then If rows(n).Selected Then selectedRows.Add(n) MsgBox(n) Select Case moveDirection Case Main.MoveDirection.Down If ((n + moveDirection) = 0) AndAlso rows(n + moveDirection).Selected = False Then selectedRows(selectedRows.Count - 1) = (n + moveDirection) thisRow = rows(n) rows.Remove(thisRow) rows.Insert(n + moveDirection, thisRow) End If Case Main.MoveDirection.Up If ((n + moveDirection) <= lastRowIndex) Then MsgBox(selectedRows(selectedRows.Count - 1)) selectedRows(selectedRows.Count - 1) = (n + moveDirection) thisRow = rows(n) rows.Remove(thisRow) rows.Insert(n + moveDirection, thisRow) End If End Select End If End If Next n ' reselect the original selected rows For n As Integer = 0 To lastRowIndex dgv.Rows(n).Selected = selectedRows.Contains(n) ' renumber the order (optional & unknown, but trivial) dgv.Rows(n).Cells(0).Value = (n + 1) Next n End Sub 

(更新)
您需要迭代行集合,测试是否选中了每个行集合,然后交换行。 为了使2个选定的行在到达顶部或底部时不相互交换,需要单独的Up和Down方法。

 ' list of hash codes of the selected rows Private Function GetSelectedRows() As List(Of Integer) Dim selR As New List(Of Integer) ' have to clear selected so the NEXT row ' doesnt cause odd behavior For n As Integer = 0 To dgv.Rows.Count - 1 If dgv.Rows(n).IsNewRow = False AndAlso dgv.Rows(n).Selected Then selR.Add(dgv.Rows(n).GetHashCode) dgv.Rows(n).Selected = False End If Next Return selR End Function ' restore original selected rows Private Sub SetSelectedRows(selRows As List(Of Integer)) For n As Integer = 0 To dgv.Rows.Count - 1 If dgv.Rows(n).IsNewRow = False Then dgv.Rows(n).Selected = selRows.Contains(dgv.Rows(n).GetHashCode) ' reset Order col: dgv.Rows(n).Cells(0).Value = n + 1 End If Next End Sub Private Sub MoveRowsUp() ' short ref Dim rows As DataGridViewRowCollection = dgv.Rows ' row index Dim thisRow As DataGridViewRow ' put selection back Dim selectedRows As List(Of Integer) ' max rows Dim LastRow = If(dgv.AllowUserToAddRows, rows.Count - 2, rows.Count - 1) selectedRows = GetSelectedRows() For n As Int32 = 0 To LastRow If rows(n).IsNewRow = False Then If (selectedRows.Contains(rows(n).GetHashCode)) AndAlso (n - 1 >= 0) AndAlso (selectedRows.Contains(rows(n - 1).GetHashCode) = False) Then thisRow = rows(n) rows.Remove(thisRow) rows.Insert(n - 1, thisRow) End If End If Next SetSelectedRows(selectedRows) End Sub Private Sub MoveRowsDn() Dim rows As DataGridViewRowCollection = dgv.Rows Dim thisRow As DataGridViewRow Dim selectedRows As New List(Of Integer) Dim LastRow = If(dgv.AllowUserToAddRows, rows.Count - 2, rows.Count - 1) selectedRows = GetSelectedRows() For n As Int32 = LastRow To 0 Step -1 If rows(n).IsNewRow = False Then If (selectedRows.Contains(rows(n).GetHashCode)) AndAlso (n + 1 <= LastRow) AndAlso (selectedRows.Contains(rows(n + 1).GetHashCode) = False) Then thisRow = rows(n) rows.Remove(thisRow) rows.Insert(n + 1, thisRow) End If End If Next SetSelectedRows(selectedRows) End Sub 

用法:

  MoveRowsUp() ' move down: MoveRowsDn() 

移动行会导致dgv重置选择。 方法首先通过并获取所选行的HashCodes列表,然后在最后重置每个Row.Selected属性。

代码更改了Cell(0)的值,因此order和Order列匹配(这意味着Order列值可变的)。

移动检查以查看此行是否在末尾或者是否还选择了目标行。 这可以防止行在到达顶部或底部时交换位置。

之前:
在此处输入图像描述

后:
在此处输入图像描述

请注意,当“Zalgo”到达底部(意味着选择了3和5)时,另一个仍然可以向下移动一个,所以它在“Ziggy”保持不变的情况下进行。 “Ziggy(3)”向下移动的能力是基于下一行/索引(仅) - 下一行不超出底部而未选择,因此它仍然可以向下移动1,而“Zalgo(5) )“ 不能。

这是我的最终代码,感谢@Plutonix,我只是将逻辑转换为扩展方法,并通过提供一组单元索引来扩展原始function以自动化单元格保存以保留其值:

 #Region " Members Summary " ' · Public Methods ' ' MoveSelectedRows(direction) ' MoveSelectedRows(direction, preserveCellsIndex) #End Region #Region " Option Statements " Option Strict On Option Explicit On Option Infer Off #End Region #Region " Imports " Imports System.Diagnostics Imports System.Runtime.CompilerServices Imports System.Windows.Forms #End Region '''  ''' Contains sofisticated extension methods for a  control. '''  '''  Public Module DataGridViewExtensions #Region " Enumerations " '''  ''' Specifies a direction for a move operation of a rows collection. '''  Public Enum RowMoveDirection As Integer '''  ''' Move row up. '''  Up = 0 '''  ''' Move row down. '''  Down = 1 End Enum #End Region #Region " Public Extension Methods " '''  ''' Moves up or down the selected row(s) of the current . '''  ''' The . ''' The row-move direction.   Public Sub MoveSelectedRows(ByVal sender As DataGridView, ByVal direction As RowMoveDirection) DoRowsMove(sender, direction) End Sub '''  ''' Moves up or down the selected row(s) of the current . '''  ''' The . ''' The row-move direction. ''' A sequence of cell indexes to preserve its cell values when moving the row(s).   Public Sub MoveSelectedRows(ByVal sender As DataGridView, ByVal direction As RowMoveDirection, ByVal preserveCellsIndex As IEnumerable(Of Integer)) DoRowsMove(sender, direction, preserveCellsIndex) End Sub #End Region #Region " Private Methods " '''  ''' Moves up or down the selected row(s) of the specified . '''  ''' The . ''' The row-move direction. ''' Optionally, a sequence of cell indexes to preserve its cell values when moving the row(s).  Private Sub DoRowsMove(ByVal dgv As DataGridView, ByVal direction As RowMoveDirection, Optional ByVal preserveCellsIndex As IEnumerable(Of Integer) = Nothing) ' Keeps tracks of a cell value to preserve, to swap them when moving rows. Dim oldCellValue As Object Dim newCellValue As Object ' Short row collection reference. Dim rows As DataGridViewRowCollection = dgv.Rows ' Keeps track of the current row. Dim curRow As DataGridViewRow ' The maximum row index. Dim lastRowIndex As Integer = If(dgv.AllowUserToAddRows, rows.Count - 2, rows.Count - 1) ' List of hash codes of the selected rows. Dim selectedRows As New List(Of Integer) ' Get the hash codes of the selected rows For i As Integer = 0 To (rows.Count - 1) If (rows(i).IsNewRow = False) AndAlso (rows(i).Selected) Then selectedRows.Add(rows(i).GetHashCode) rows(i).Selected = False End If Next i ' Move the selected rows up or down. Select Case direction Case RowMoveDirection.Up For i As Integer = 0 To lastRowIndex If Not rows(i).IsNewRow Then If (selectedRows.Contains(rows(i).GetHashCode)) AndAlso (i - 1 >= 0) AndAlso (Not selectedRows.Contains(rows(i - 1).GetHashCode)) Then curRow = rows(i) rows.Remove(curRow) rows.Insert(i - 1, curRow) If preserveCellsIndex IsNot Nothing Then For Each cellIndex As Integer In preserveCellsIndex oldCellValue = curRow.Cells(cellIndex).Value newCellValue = rows(i).Cells(cellIndex).Value rows(i).Cells(cellIndex).Value = oldCellValue curRow.Cells(cellIndex).Value = newCellValue Next cellIndex End If End If End If Next i Case RowMoveDirection.Down For i As Integer = lastRowIndex To 0 Step -1 If Not rows(i).IsNewRow Then If (selectedRows.Contains(rows(i).GetHashCode)) AndAlso (i + 1 <= lastRowIndex) AndAlso (Not selectedRows.Contains(rows(i + 1).GetHashCode)) Then curRow = rows(i) rows.Remove(curRow) rows.Insert(i + 1, curRow) If preserveCellsIndex IsNot Nothing Then For Each cellIndex As Integer In preserveCellsIndex oldCellValue = curRow.Cells(cellIndex).Value newCellValue = rows(i).Cells(cellIndex).Value rows(i).Cells(cellIndex).Value = oldCellValue curRow.Cells(cellIndex).Value = newCellValue Next cellIndex End If End If End If Next i End Select ' Restore selected rows. For i As Integer = 0 To (rows.Count - 1) If Not rows(i).IsNewRow Then rows(i).Selected = selectedRows.Contains(rows(i).GetHashCode) End If Next i End Sub #End Region End Module