1

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();
            }
        }
4
  • 2
    Just a guess, but perhaps table.AcceptChanges might help things Commented Aug 30, 2011 at 18:00
  • @Conrad Frix -Make that an answer, that did the trick! Now I just have to figure out how I can reuse that code (I'm going to end up with 5-8 gridviews I want to be able to drag between). Commented Aug 30, 2011 at 18:09
  • ok I put in as an answer and included my thinking behind it. If I'm wrong enough someone will correct me, or provide a more complete answer Commented Aug 30, 2011 at 21:05
  • @Shyamsundarshah Please stop adding the visual studio tag to these questions. It is not valid. Commented Jun 30, 2013 at 11:46

2 Answers 2

2

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.

Sign up to request clarification or add additional context in comments.

Comments

2

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.

2 Comments

@Enigmativity -I'm eager to reuse code here, but I"m new to lambda expressions, any good intro article?
@MAW74656 - To start learning lambdas just think of them as "inline methods". Writing Func<string, int> GetLength = t => t.Length; is the same as private int GetLength(string t) { return t.Length; } when calling the code - int len = GetLength("Hello");. Start from there. Also, any delegate (Func, Action, EventHandler<>, etc) can use the lambda syntax. Otherwise, search StackOverflow as there are tonnes of examples here.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.