简体   繁体   中英

Drag and Drop is not working in C#

I figured out how to drag rows between datagridviews from how to drag gridview row from one grid to another , but now I have a problem. I can drag the row from gridPODetails to DataGridView1. I can drag the row back to gridPODetails from DataGridView1. But after that I get nothing. I would expect to be able to drag back and forth indefinately, but I can only go there and back. What could be causing this and how to correct?

 private void gridPODetails_MouseDown(object sender, MouseEventArgs e)
        {
            DataGridView.HitTestInfo info = gridPODetails.HitTest(e.X, e.Y);

            if (info.RowIndex >= 0)
            {
                DataRow view = ((DataTable)(gridPODetails.DataSource)).Rows[info.RowIndex];
                if (view != null)
                {
                    gridPODetails.DoDragDrop(view, DragDropEffects.Copy);
                }
            }
        }

        private void gridPODetails_DragEnter(object sender, DragEventArgs e)
        {
            e.Effect = DragDropEffects.Copy;
        }

        private void gridPODetails_DragDrop(object sender, DragEventArgs e)
        {
            DataGridView grid = sender as DataGridView;
            DataTable table = grid.DataSource as DataTable;
            DataRow row = e.Data.GetData(typeof(DataRow)) as DataRow;

            if (row != null && table != null && row.Table != table)
            {
                table.ImportRow(row);
                row.Delete();
            }
        }

        private void dataGridView1_MouseDown(object sender, MouseEventArgs e)
        {
            DataGridView.HitTestInfo info = dataGridView1.HitTest(e.X, e.Y);

            if (info.RowIndex >= 0)
            {
                DataRow view = ((DataTable)(dataGridView1.DataSource)).Rows[info.RowIndex];
                if (view != null)
                {
                    dataGridView1.DoDragDrop(view, DragDropEffects.Copy);
                }
            }
        }

        private void dataGridView1_DragEnter(object sender, DragEventArgs e)
        {
            e.Effect = DragDropEffects.Copy;
        }

        private void dataGridView1_DragDrop(object sender, DragEventArgs e)
        {
            DataGridView grid = sender as DataGridView;
            DataTable table = grid.DataSource as DataTable;
            DataRow row = e.Data.GetData(typeof(DataRow)) as DataRow;

            if (row != null && table != null && row.Table != table)
            {
                table.ImportRow(row);
                row.Delete();
            }
        }

Adding table.AcceptChanges() after row.Delete() should allow you to move the row back forth between tables.

The reason for this may be because importing a row that previously was deleted can cause issues.

In response to MAW74656's comment under the question I've put together the method I would use if I were going to wire-up multiple grids to do the drag-and-drop.

In essence I try to create a lambda to group all of this functionality inside a single method - it could be done as it's own method if need be though to allow multiple callers.

Here it is:

Func<DataGridView, IEnumerable<Action>> configureDragDrop = grid =>
{
    var dataTable = grid.DataSource as DataTable;

    /* Event handler definitions here - see below */

    grid.MouseDown += mds;
    grid.DragEnter += des;
    grid.DragDrop += dds;

    return new Action[]
    {
        () => grid.MouseDown -= mds,
        () => grid.DragEnter -= des,
        () => grid.DragDrop -= dds,
    };
};

This code allows me to write this:

        // form-level field
        private List<Action> removeHandlers = new List<Action>();

        // in the method where `configureDragDrop` is defined
        removeHandlers.AddRange(configureDragDrop(gridPODetails));
        removeHandlers.AddRange(configureDragDrop(dataGridView1));
        removeHandlers.AddRange(configureDragDrop(dataGridView2));
        removeHandlers.AddRange(configureDragDrop(dataGridView3));
        removeHandlers.AddRange(configureDragDrop(dataGridView4));
        removeHandlers.AddRange(configureDragDrop(dataGridView5));
        removeHandlers.AddRange(configureDragDrop(dataGridView6));
        removeHandlers.AddRange(configureDragDrop(dataGridView7));
        // etc

When I'm closing down my form I can then remove all the handlers in one line:

        Array.ForEach(removeHandlers.ToArray(), rh => rh.Invoke());

The event handlers look very similar to the original code - just now in lambda form.

MouseDown :

            MouseEventHandler mds = (smd, emd) =>
            {
                var info = grid.HitTest(emd.X, emd.Y);
                if (info.RowIndex >= 0)
                {
                    var dr = dataTable.Rows[info.RowIndex];
                    if (dr != null)
                    {
                        grid.DoDragDrop(dr, DragDropEffects.Copy);
                    }
                }
            };

DragEnter :

            DragEventHandler des = (sde, ede) =>
            {
                ede.Effect = DragDropEffects.Copy;
            };

DragDrop :

            DragEventHandler dds = (sdd, edd) =>
            {
                var dr = edd.Data.GetData(typeof(DataRow)) as DataRow;
                if (dr != null)
                {
                    var dst = dataTable;
                    var src = dr.Table;
                    if (dst != src)
                    {
                        dst.ImportRow(dr);
                        dr.Delete();
                        src.AcceptChanges();
                        dst.AcceptChanges();
                    }
                }
            };

I hope this helps.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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