DataGridView выбранная строка перемещается вверх и вниз

Как я могу разрешить перемещение выбранных строк в DataGridView (DGV) вверх или вниз. Я делал это раньше с помощью ListView. К сожалению, для меня замена DGV не является вариантом (проклятие). Кстати, источник данных DGV-это общая коллекция.

DGV имеет две кнопки сбоку, да, вверх и вниз. Может кто-нибудь помочь мне точку в правильном направлении. У меня есть код, который я использовал для ListView, если это поможет (это не помогло мне).

13 ответов


Если вы программно измените порядок элементов в вашей коллекции, DGV должен отражать это автоматически.

небрежный, наполовину рабочий пример:

List<MyObj> foo = DGV.DataSource;
int idx = DGV.SelectedRows[0].Index;
int value = foo[idx];
foo.Remove(value);
foo.InsertAt(idx+1, value)

некоторые из этой логики могут быть неправильными,и это может быть не самый эффективный подход. Кроме того, он не учитывает выбор нескольких строк.

Хм, последнее, если вы используете стандартный список или коллекцию, это не будет идти так гладко. Список и коллекция on't испускает события, которые DGV находит полезными для привязки данных. Вы можете "рыгать" привязку данных каждый раз, когда вы меняете коллекцию, но лучшим решением было бы использовать систему.ComponentModel.Класс bindinglist. При изменении порядка списка привязки DGV должен автоматически отражать это изменение.


чтобы расширить ответ Yoopergeek, вот что у меня есть. Я не использовал источник данных (данные сбрасываются в реестр при закрытии формы и перезагружаются при загрузке формы)

в этом примере строки не будут перемещены из сетки и потеряны, а также повторно выберите ячейку, в которой был человек.

чтобы упростить копирование / вставку, я изменил, поэтому вам нужно только изменить "gridTasks" на имя вашего DataGridView, а не переименовывать его во всем код.

это решение работает только для одной ячейки/строки.

private void btnUp_Click(object sender, EventArgs e)
{
    DataGridView dgv = gridTasks;
    try
    {
        int totalRows = dgv.Rows.Count;
        // get index of the row for the selected cell
        int rowIndex = dgv.SelectedCells[ 0 ].OwningRow.Index;
        if ( rowIndex == 0 )
            return;
        // get index of the column for the selected cell
        int colIndex = dgv.SelectedCells[ 0 ].OwningColumn.Index;
        DataGridViewRow selectedRow = dgv.Rows[ rowIndex ];
        dgv.Rows.Remove( selectedRow );
        dgv.Rows.Insert( rowIndex - 1, selectedRow );
        dgv.ClearSelection();
        dgv.Rows[ rowIndex - 1 ].Cells[ colIndex ].Selected = true;
    }
    catch { }
}

private void btnDown_Click(object sender, EventArgs e)
{
    DataGridView dgv = gridTasks;
    try
    {
        int totalRows = dgv.Rows.Count;
        // get index of the row for the selected cell
        int rowIndex = dgv.SelectedCells[ 0 ].OwningRow.Index;
        if ( rowIndex == totalRows - 1 )
            return;
        // get index of the column for the selected cell
        int colIndex = dgv.SelectedCells[ 0 ].OwningColumn.Index;
        DataGridViewRow selectedRow = dgv.Rows[ rowIndex ];
        dgv.Rows.Remove( selectedRow );
        dgv.Rows.Insert( rowIndex + 1, selectedRow );
        dgv.ClearSelection();
        dgv.Rows[ rowIndex + 1 ].Cells[ colIndex ].Selected = true; 
    }
    catch { }
}

Это должно работать. Я использую BindingSource вместо привязки моего списка непосредственно к DataGridView:

    private List<MyItem> items = new List<MyItem> {
        new MyItem {Id = 0, Name = "Hello"},
        new MyItem {Id = 1, Name = "World"},
        new MyItem {Id = 2, Name = "Foo"},
        new MyItem {Id = 3, Name = "Bar"},
        new MyItem {Id = 4, Name = "Scott"},
        new MyItem {Id = 5, Name = "Tiger"},
    };

    private BindingSource bs;
    private void Form1_Load(object sender, EventArgs e)
    {
        bs = new BindingSource(items, string.Empty);
        dataGridView1.DataSource = bs;
    }

    private void button1_Click(object sender, EventArgs e)
    {
        if (bs.Count <= 1) return; // one or zero elements

        int position = bs.Position;
        if (position <= 0) return;  // already at top

        bs.RaiseListChangedEvents = false;

        MyItem current = (MyItem)bs.Current;
        bs.Remove(current);

        position--;

        bs.Insert(position, current);
        bs.Position = position;

        bs.RaiseListChangedEvents = true;
        bs.ResetBindings(false);
    }

    private void button2_Click(object sender, EventArgs e)
    {
        if (bs.Count <= 1) return; // one or zero elements

        int position = bs.Position;
        if (position == bs.Count - 1) return;  // already at bottom

        bs.RaiseListChangedEvents = false;

        MyItem current = (MyItem)bs.Current;
        bs.Remove(current);

        position++;

        bs.Insert(position, current);
        bs.Position = position;

        bs.RaiseListChangedEvents = true;
        bs.ResetBindings(false);
    }

    public class MyItem
    {
        public int Id { get; set; }
        public String Name { get; set; }
    }

сначала заполните datagridview, например, вы получили таблицу с 3 colums

DataTable table = new DataTable();
table.Columns.Add("col1");
table.Columns.Add("col2");
table.Columns.Add("col3");
foreach (var i in yourTablesource(db,list,etc))
{
  table.Rows.Add(i.col1, i.col2, i.col2);
}
datagridview1.DataSource = table;

затем, на кнопку "вверх", нажмите кнопку

int rowIndex;
private void btnUp_Click(object sender, EventArgs e)
{
    rowIndex = datagridview1.SelectedCells[0].OwningRow.Index;
    DataRow row = table.NewRow();
    row[0] = datagridview1.Rows[rowIndex].Cells[0].Value.ToString();
    row[1] = datagridview1.Rows[rowIndex].Cells[1].Value.ToString();
    row[2] = datagridview1.Rows[rowIndex].Cells[2].Value.ToString();
    if (rowIndex > 0)
    {
        table.Rows.RemoveAt(rowIndex);
        table.Rows.InsertAt(row, rowIndex - 1);
        datagridview1.ClearSelection();
        datagridview1.Rows[rowIndex - 1].Selected = true;
    }
}

сделайте то же самое для кнопки вниз, просто измените row index С rowIndex - 1 to rowindex + 1 в своем buttonDown_Click метод


искал эту кнопку вверх/вниз и рад, что нашел это. Лучше поставить bs.RaiseListChangedEvents = false оператор после возврата или он не работает все время.

и в C#3.0 вы можете добавить два метода расширения в BindingSource следующим образом:

public static class BindingSourceExtension
{
    public static void MoveUp( this BindingSource aBindingSource )
    {
        int position = aBindingSource.Position;
        if (position == 0) return;  // already at top

        aBindingSource.RaiseListChangedEvents = false;

        object current = aBindingSource.Current;
        aBindingSource.Remove(current);

        position--;

        aBindingSource.Insert(position, current);
        aBindingSource.Position = position;

        aBindingSource.RaiseListChangedEvents = true;
        aBindingSource.ResetBindings(false);
    }

    public static void MoveDown( this BindingSource aBindingSource )
    {
        int position = aBindingSource.Position;
        if (position == aBindingSource.Count - 1) return;  // already at bottom

        aBindingSource.RaiseListChangedEvents = false;

        object current = aBindingSource.Current;
        aBindingSource.Remove(current);

        position++;

        aBindingSource.Insert(position, current);
        aBindingSource.Position = position;

        aBindingSource.RaiseListChangedEvents = true;
        aBindingSource.ResetBindings(false);
    }
}

наконец, хорошее использование методов расширения вместо всех этих плохих примеров строк.. ;-)


   DataGridViewRow BeginingRow = new DataGridViewRow();
   int BeginingRowIndex ;   
        private void DataGridView1_CellMouseUp(object sender, DataGridViewCellMouseEventArgs e)
    {
        if (e.Button != MouseButtons.Left ||e.RowIndex < 0 ) return;
            if (BeginingRowIndex > e.RowIndex)
            {
                DataGridView1.Rows.Insert(e.RowIndex);
                foreach (DataGridViewCell cellules in BeginingRow.Cells)
                {
                    DataGridView1.Rows[e.RowIndex].Cells[cellules.ColumnIndex].Value = cellules.Value;
                }
                DataGridView1.Rows.RemoveAt(BeginingRowIndex + 1);

            }
            else
            {
                DataGridView1.Rows.Insert(e.RowIndex +1);
                foreach (DataGridViewCell cellules in BeginingRow.Cells)
                {
                    DataGridView1.Rows[e.RowIndex+1].Cells[cellules.ColumnIndex].Value = cellules.Value;
                }
                DataGridView1.Rows.RemoveAt(BeginingRowIndex);
            }

            DataGridView1.RowsDefaultCellStyle.ApplyStyle(BeginingRow.DefaultCellStyle);
            DataGridView1.Rows[e.RowIndex].Selected = true;
    }

    private void DataGridView1_CellMouseDown(object sender, DataGridViewCellMouseEventArgs e)
    {
        if (e.Button != MouseButtons.Left ||e.RowIndex < 0 ) return;
                BeginingRowIndex = e.RowIndex;
                BeginingRow = DataGridView1.Rows[BeginingRowIndex];
                BeginingRow.DefaultCellStyle = DataGridView1.Rows[BeginingRowIndex].DefaultCellStyle;
    }

private void butUp_Click(object sender, EventArgs e)
{
    DataTable dtTemp = gridView.DataSource as DataTable;

    object[] arr = dtTemp.Rows[0].ItemArray;
    for (int i = 1; i < dtTemp.Rows.Count; i++)
    {
        dtTemp.Rows[i - 1].ItemArray = dtTemp.Rows[i].ItemArray;
    }
    dtTemp.Rows[dtTemp.Rows.Count - 1].ItemArray = arr;

}
private void butDown_Click(object sender, EventArgs e)
{
    DataTable dtTemp = gridView.DataSource as DataTable;

    object[] arr = dtTemp.Rows[dtTemp.Rows.Count - 1].ItemArray;
    for (int i = dtTemp.Rows.Count - 2; i >= 0; i--)
    {
        dtTemp.Rows[i + 1].ItemArray = dtTemp.Rows[i].ItemArray;
    }
    dtTemp.Rows[0].ItemArray = arr;
}

это самое короткое решение, которое я нашел для проблемы, и я просто немного переработал код, найденный в:

http://dotnetspeaks.net/post/Moving-GridView-Rows-Up-Down-in-a-GridView-Control.aspx

<body>
<form id="form1" runat="server">
<asp:GridView ID="GridView1" Font-Names="Verdana" Font-Size="9pt" runat="server" OnRowCreated="GridView1_RowCreated"
    AutoGenerateColumns="False" CellPadding="4" BorderColor="#507CD1" BorderStyle="Solid">
    <Columns>
        <asp:TemplateField HeaderText="First Name">
            <ItemTemplate>
                <asp:Label ID="txtFirstName" runat="server" Text='<%# Eval("FirstName") %>' />
            </ItemTemplate>
        </asp:TemplateField>
    </Columns>
    <HeaderStyle BackColor="#507CD1" Font-Bold="True" ForeColor="White" />
    <AlternatingRowStyle BackColor="White" />
</asp:GridView>

<asp:Button ID="btnUp" runat="server" Text="Up" OnClick="btnUp_Click"/>
<asp:Button ID="btnDown" runat="server" Text="Down"  OnClick="btnDown_Click" />
</form>

и за код...

public int SelectedRowIndex { get; set; }


    protected void Page_Load(object sender, EventArgs e)
    {
        if (!IsPostBack)
        {
            //Test Records  
            GridView1.DataSource = Enumerable.Range(1, 5).Select(a => new
            {
                FirstName = String.Format("First Name {0}", a),
                LastName = String.Format("Last Name {0}", a),
            });
            GridView1.DataBind();
        }  
    }

    protected void GridView1_RowCreated(object sender, GridViewRowEventArgs e)
    {
        if (e.Row.RowType == DataControlRowType.DataRow)
        {
            e.Row.Attributes["onmouseover"] = "this.style.cursor='pointer'";
            e.Row.ToolTip = "Click to select row";
            e.Row.Attributes["onclick"] = Page.ClientScript.GetPostBackClientHyperlink(GridView1, "Select$" + e.Row.RowIndex);
        }
    }


    protected void btnUp_Click(object sender, EventArgs e)
    {
        var rows = GridView1.Rows.Cast<GridViewRow>().Where(a => a != GridView1.SelectedRow).ToList();
        //If First Item, insert at end (rotating positions)  
        if (GridView1.SelectedRow.RowIndex.Equals(0))
        {
            rows.Add(GridView1.SelectedRow);
            SelectedRowIndex = GridView1.Rows.Count -1;
        }
        else
        {
            SelectedRowIndex = GridView1.SelectedRow.RowIndex - 1;
            rows.Insert(GridView1.SelectedRow.RowIndex - 1, GridView1.SelectedRow);
        }
        RebindGrid(rows);
    }

    protected void btnDown_Click(object sender, EventArgs e)
    {
        var rows = GridView1.Rows.Cast<GridViewRow>().Where(a => a != GridView1.SelectedRow).ToList();
        //If Last Item, insert at beginning (rotating positions)  
        if (GridView1.SelectedRow.RowIndex.Equals(GridView1.Rows.Count - 1))
        {
            rows.Insert(0, GridView1.SelectedRow);
            SelectedRowIndex = 0;
        }
        else
        {
            SelectedRowIndex = GridView1.SelectedRow.RowIndex + 1;
            rows.Insert(GridView1.SelectedRow.RowIndex + 1, GridView1.SelectedRow);
        }
        RebindGrid(rows);
    }

    private void RebindGrid(IEnumerable<GridViewRow> rows)
    {
        GridView1.DataSource = rows.Select(a => new
        {
            FirstName = ((Label)a.FindControl("txtFirstName")).Text,
        }).ToList();

        GridView1.SelectedIndex = SelectedRowIndex;
        GridView1.DataBind();
    }

3

private void buttonX8_Click (отправитель объекта, EventArgs e) / / вниз { Сетка DataGridViewX = dataGridViewX1; пытаться { int totalRows = сетка.Строки.Рассчитывать; инт индекса IDx = сетки.SelectedCells[0].OwningRow.Индекс; если (idx == totalRows-1 ) возвращаться; int col = сетка.SelectedCells[0].OwningColumn.Индекс; DataGridViewRowCollection rows = сетка.Строки; Ячейки datagridviewrow строки = строки[индекс]; строки.Удалить (строка); строки.Вставить (idx + 1, строка); сетка.Не(); сетка.Строки[idx + 1].Клетки[col].Selected = true;

      private void buttonX8_Click(object sender, EventArgs e)//down
    {
        DataGridViewX grid = dataGridViewX1;
        try
        {
            int totalRows = grid.Rows.Count;
            int idx = grid.SelectedCells[0].OwningRow.Index;
            if (idx == totalRows - 1 )
                return;
            int col = grid.SelectedCells[0].OwningColumn.Index;
            DataGridViewRowCollection rows = grid.Rows;
            DataGridViewRow row = rows[idx];
            rows.Remove(row);
            rows.Insert(idx + 1, row);
            grid.ClearSelection();
            grid.Rows[idx + 1].Cells[col].Selected = true;

        }
        catch { }
    }

ответ SchlaWiener работал хорошо, и я просто хочу добавить к нему что-то:

private void button1_Click(object sender, EventArgs e) //The button to move up
{
    int position = bs.Position;

    //.......neglected.......

    dataGridView1.ClearSelection();
    dataGridView1.Rows[position].Selected = true;
    bs.MovePrevious();

}

добавление этих 3 строк внизу, чтобы также переместить выбор (как bindingSource, так и dataGridView), чтобы мы могли непрерывно нажимать на нижнюю часть, чтобы переместить строку вверх.

для перемещения вниз просто вызовите bs.MoveNext ()

(У меня еще недостаточно репутации, чтобы опубликовать комментарий)


решение с привязкой к данным с поддержкой множественного выбора используйте SharpDevelop 4.4 для преобразования в C#.

<Extension()>
Sub MoveSelectionUp(dgv As DataGridView)
    If dgv.CurrentCell Is Nothing Then Exit Sub
    dgv.CurrentCell.OwningRow.Selected = True
    Dim items = DirectCast(dgv.DataSource, BindingSource).List
    Dim selectedIndices = dgv.SelectedRows.Cast(Of DataGridViewRow).Select(Function(row) row.Index).Sort
    Dim indexAbove = selectedIndices(0) - 1
    If indexAbove = -1 Then Exit Sub
    Dim itemAbove = items(indexAbove)
    items.RemoveAt(indexAbove)
    Dim indexLastItem = selectedIndices(selectedIndices.Count - 1)

    If indexLastItem = items.Count Then
        items.Add(itemAbove)
    Else
        items.Insert(indexLastItem + 1, itemAbove)
    End If
End Sub

<Extension()>
Sub MoveSelectionDown(dgv As DataGridView)
    If dgv.CurrentCell Is Nothing Then Exit Sub
    dgv.CurrentCell.OwningRow.Selected = True
    Dim items = DirectCast(dgv.DataSource, BindingSource).List
    Dim selectedIndices = dgv.SelectedRows.Cast(Of DataGridViewRow).Select(Function(row) row.Index).Sort
    Dim indexBelow = selectedIndices(selectedIndices.Count - 1) + 1
    If indexBelow >= items.Count Then Exit Sub
    Dim itemBelow = items(indexBelow)
    items.RemoveAt(indexBelow)
    Dim indexAbove = selectedIndices(0) - 1
    items.Insert(indexAbove + 1, itemBelow)
End Sub

существует гораздо более простой способ, которым большинство сообщений здесь (на мой взгляд). Выполнение действия для нажатия кнопки" вверх " - это в основном просто обмен строками с указанным выше. Если вы сами контролируете значения (как был задан вопрос), вам просто нужно поменять значения строк. Быстро и просто!

Примечание: это работает только тогда, когда multiselect отключен на datagrid! Как вы можете сказать, я обращаю внимание только на элемент в индексе 0 в SelectedRows коллекция.

вот что я использовал:

    private void btnUp_Click(object sender, EventArgs e)
    {
        var row = dgvExportLocations.SelectedRows[0];

        if (row != null && row.Index > 0)
        {
            var swapRow = dgvExportLocations.Rows[row.Index - 1];
            object[] values = new object[swapRow.Cells.Count];

            foreach (DataGridViewCell cell in swapRow.Cells)
            {
                values[cell.ColumnIndex] = cell.Value;
                cell.Value = row.Cells[cell.ColumnIndex].Value;
            }

            foreach (DataGridViewCell cell in row.Cells)
                cell.Value = values[cell.ColumnIndex];

            dgvExportLocations.Rows[row.Index - 1].Selected = true;//have the selection follow the moving cell
        }
    }

чтобы выполнить щелчок" вниз", вы также можете сделать противоположное, та же логика


попробуйте это:

    private void buttonX9_Click(object sender, EventArgs e)//up
    {

        DataGridViewX grid = dataGridViewX1;
        try
        {
            int totalRows = grid.Rows.Count;
            int idx = grid.SelectedCells[0].OwningRow.Index;
            if (idx == 0)
                return;
            int col = grid.SelectedCells[0].OwningColumn.Index;
            DataGridViewRowCollection rows = grid.Rows;
            DataGridViewRow row = rows[idx];
            rows.Remove(row);
            rows.Insert(idx - 1, row);
            grid.ClearSelection();
            grid.Rows[idx - 1].Cells[col].Selected = true;

        }
        catch { }

    }