简体   繁体   English

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

[英]Move up or down little complex DataGridView rows with multi-selection

I have a DataGridView like this: 我有一个像这样的DataGridView:

在此输入图像描述

Now, In C# or else VB.Net , with a button, I would like to move up or down one position the selected rows, how I could do it?. 现在,在C#VB.Net中 ,有了一个按钮,我想向上或向下移动所选行的一个位置,我怎么能这样做? The multi selection requisite complicate me this. 多选必备使我复杂化。

The files that appear in the DataGridView will be combined into a single executable file, then, the files will be executed in the order of the " Order " column, so the " Order " value should be inmutable when moving rows up or down. 出现在DataGridView中的文件将合并为一个可执行文件,然后,文件将按“ Order ”列的顺序执行,因此在向上或向下移动行时,“ Order ”值应该是不可变的。

I'm not using any data source. 我没有使用任何数据源。


I've tried to analyze this sample from MSDN , it consists in some extension methods, but it takes a datatable and datasource, I don't have any dissapoint to use a datatable and datasource but just I don't know how to adapt the code-sample for my DataGridView. 我试图从MSDN分析这个示例,它包含一些扩展方法,但它需要一个数据表和数据源,我没有任何使用数据表和数据源的失望但只是我不知道如何适应我的DataGridView的代码示例。 Anyways the sample does not support multi selection: 无论如何,样本不支持多选:

Move rows up/down and remember order for DataGridView and ListBoxs data bound 向上/向下移动行并记住DataGridView和ListBoxs数据绑定的顺序

I also have seen some C# questions about this on StackOverflow but they asks for single row selection: 我也在StackOverflow上看到了一些关于这个问题的C#问题,但他们要求选择单行:

How to move gridview selected row up/down on KeyUp or Keydown press 如何在KeyUp或Keydown按下上移/下移gridview选择的行

DataGridView Selected Row Move UP and DOWN DataGridView选定的行向上和向下移动

Then, I don't have an starting point, just these methods to move a SINGLE row that also does not preserve the Order value, if someone could guide me to extend the functionality for my needs: Private Sub Button_MoveUp_Click(sender As Object, e As EventArgs) _ Handles Button_MoveUp.Click 然后,我没有一个起点,只是这些方法移动一个也不保留Order值的SINGLE行,如果有人可以指导我扩展我的需求的功能: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 UPDATE

I'm trying @Plutonix approach (with a little modification), the only problem is that it does not move properly the selected rows to UP direction. 我正在尝试使用@Plutonix方法(稍作修改),唯一的问题是它没有将所选行正确移动到UP方向。

Steps to reprduce the issue: 重新定位问题的步骤:

  1. Select two rows that are together (eg. row index 2 and row index 3, NOT row index 2 and row index 4) 选择两个在一起的行(例如,行索引2和行索引3,非行索引2和行索引4)

  2. Try to move the rows to UP direction. 尝试将行移动到向上方向。

How I could fix it?. 我怎么能解决它?

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

(Updated) (更新)
You need to iterate the rows collection, test if each is selected, then swap rows. 您需要迭代行集合,测试是否选中了每个行集合,然后交换行。 In order to keep 2 selected rows from swapping with each other when they get to the top or bottom, a separate Up and Down method are needed. 为了防止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

Usage: 用法:

 MoveRowsUp()
 ' move down:
 MoveRowsDn()

Moving the rows causes the dgv to reset the selections. 移动行会导致dgv重置选择。 The methods first go thru and get a list of the HashCodes of the selected rows, then at the end resets each Row.Selected property based on that. 方法首先通过并获得所选行的HashCodes列表,然后在最后重置每个Row.Selected属性。

The code changes the value of Cell(0) so the order and Order column match (which means the Order column value is mutable). 代码更改了Cell(0)的值,因此order和Order列匹配(这意味着Order列值可变的)。

Moving checks to see both if this row is at the end OR if the row at the destination is also selected. 移动检查以查看此行是否在末尾或者是否也选择了目标行。 This prevents rows from swapping places when they get to the top or bottom. 这可以防止行在到达顶部或底部时交换位置。

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

After: 后:
在此输入图像描述

Note that when "Zalgo" got to the bottom (meaning 3 and 5 were selected), the other one could still move down one, so it did while "Ziggy" stayed put. 请注意,当“Zalgo”到达底部(意味着选择了3和5)时,另一个仍然可以向下移动一个,所以它在“Ziggy”保持不变的情况下完成。 The ability of "Ziggy(3)" to move down or not is based on the next row/index (only) - the next row is not beyond the bottom AND not selected so it can still move down 1, while "Zalgo (5)" could not. “齐格(3)”的向下移动或不的能力是基于下一行/索引(只) -下一行是不超过底部不是选择,以便它仍然可以向下移动1,而“Zalgo(5 )“ 不能。

This is my final code, all thanks goes to @Plutonix, I just translated the logic to extension methods and also extended the original functionality to automate a cell preservation by giving a collection of cell indexes to preserve its values: 这是我的最终代码,所有感谢@Plutonix,我只是将逻辑转换为扩展方法,并通过提供一组单元索引来扩展原始功能以自动化单元格保存以保留其值:

#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

''' <summary>
''' Contains sofisticated extension methods for a <see cref="DataGridView"/> control.
''' </summary>
''' <remarks></remarks>
Public Module DataGridViewExtensions

#Region " Enumerations "

    ''' <summary>
    ''' Specifies a direction for a move operation of a rows collection.
    ''' </summary>
    Public Enum RowMoveDirection As Integer

        ''' <summary>
        ''' Move row up.
        ''' </summary>
        Up = 0

        ''' <summary>
        ''' Move row down.
        ''' </summary>
        Down = 1

    End Enum

#End Region

#Region " Public Extension Methods "

    ''' <summary>
    ''' Moves up or down the selected row(s) of the current <see cref="DataGridView"/>.
    ''' </summary>
    ''' <param name="sender">The <see cref="DataGridView"/>.</param>
    ''' <param name="direction">The row-move direction.</param>
    <DebuggerStepThrough>
    <Extension>
    Public Sub MoveSelectedRows(ByVal sender As DataGridView,
                                ByVal direction As RowMoveDirection)

        DoRowsMove(sender, direction)

    End Sub

    ''' <summary>
    ''' Moves up or down the selected row(s) of the current <see cref="DataGridView"/>.
    ''' </summary>
    ''' <param name="sender">The <see cref="DataGridView"/>.</param>
    ''' <param name="direction">The row-move direction.</param>
    ''' <param name="preserveCellsIndex">A sequence of cell indexes to preserve its cell values when moving the row(s).</param>
    <DebuggerStepThrough>
    <Extension>
    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 "

    ''' <summary>
    ''' Moves up or down the selected row(s) of the specified <see cref="DataGridView"/>.
    ''' </summary>
    ''' <param name="dgv">The <see cref="DataGridView"/>.</param>
    ''' <param name="direction">The row-move direction.</param>
    ''' <param name="preserveCellsIndex">Optionally, a sequence of cell indexes to preserve its cell values when moving the row(s).</param>
    <DebuggerStepThrough>
    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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM