c# - 通过多选向上或向下移动复杂的 DataGridView 行

标签 c# .net vb.net winforms datagridview

我有一个像这样的 DataGridView:

enter image description here

现在,在 C#VB.Net 中,我想通过一个按钮将所选行向上或向下移动一个位置,我该怎么做?。多重选择的要求使我变得复杂。

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

我没有使用任何数据源。


我已经尝试分析来自 MSDN 的这个示例,它包含一些扩展方法,但它需要一个数据表和数据源,我对使用数据表和数据源没有任何失望但是只是我不知道如何为我的 DataGridView 调整代码示例。 无论如何,示例不支持多选:

Move rows up/down and remember order for DataGridView and ListBoxs data bound

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

How to move gridview selected row up/down on KeyUp or Keydown press

DataGridView Selected Row Move UP and DOWN

然后,我没有起点,只有这些方法来移动也不保留 Order 值的 SINGLE 行,如果有人可以指导我扩展我需要的功能: Private Sub Button_MoveUp_Click(sender As Object, e As 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 方法(稍作修改),唯一的问题是它没有正确地将选定的行移动到向上方向。

重现问题的步骤:

  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) <= lastRowIndex) AndAlso (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 重置选择。这些方法首先获取所选行的 HashCode 列表,然后在最后根据该列表重置每个 Row.Selected 属性。

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

如果此行位于末尾如果目标行也被选中,则移动检查两者。这可以防止行在到达顶部或底部时交换位置。

之前:
enter image description here

之后:
enter image description here

请注意,当“Zalgo”到达底部(意味着选择了 3 和 5)时,另一个仍然可以向下移动一个,所以它会这样做,而“Ziggy”则留在原地。 “Ziggy(3)”是否向下移动的能力取决于下一行/索引(仅)- 下一行不超出底部 AND 未被选中,因此它仍然可以向下移动1,而“Zalgo (5)”则不能。

关于c# - 通过多选向上或向下移动复杂的 DataGridView 行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30832922/

相关文章:

c# - 首先在 Entity Framework 5 代码中完全忽略基类/接口(interface)

VB.NET 相当于 VBA 函数中的可选 Range 参数

c# - EF Core 创建多个外键列

c# - 序列化和发送 Protocol Buffers 消息

c# - 在 Property Getter 中使用 Dispatcher.Invoke()

c# - c# 模型的 HasChanged 方法

c# - 从 .Net v4.5 升级到 .Net v4.5.2 后未声明元素验证错误

c# - 将整数格式化为八进制

c# - 如果我在处理 WCF 请求时停止我的 Windows 服务,会发生什么情况?

c# - 允许 ASP.NET MVC URL 中的所有扩展