Guillaume
Guillaume

Reputation: 41

Drag and Drop between two Datagrid in WPF (C#)

Sorry for my English, this is not my native language. Please tell me if you don't understand something.

I'm starting C# and WPF, and I need to implement a drag and drop functionality between two datagrid. I already searched a lot but I don't find anything that helps me. It always shows how to do drag and drop between two different controls, or only in the same datagrid, and I'm not able to adapt these answers to my need because I don't understand some parts of the solutions. So I came here to ask a really precise question : How to implement drag and drop between two datagrids ?

I would be very grateful if you could help me.

Upvotes: 3

Views: 8484

Answers (2)

Quentin Couderc
Quentin Couderc

Reputation: 86

for that you need two Datagrid feed list or observableCollection like this in xaml:

<DataGrid AllowDrop="True" Name="dg1" Margin="10,50,10,30" Grid.Column="1">
    //Set your column and what you want
</DataGrid>
<DataGrid Name="dg2" AllowDrop="True" Margin="10,50,10,30" Grid.Column="2">
    //Set your column and what you want
</DataGrid>

I let you insert the source of Datagrid with :

dg1.ItemSource = "yourlist1";

dg2.ItemSource = "yourlist2";

Once the source fill in the datagrid add this to the top of your code c#:

namespace YourAppName
{
    public partial class MainWindow : Window
    {
        public delegate Point GetPosition(IInputElement element);
        int rowIndex = -1;
        string dgName;
        public MainWindow()
        {
            dg1.PreviewMouseLeftButtonDown += new MouseButtonEventHandler(DgSupp_PreviewMouseLeftButtonDown);
            dg1.Drop += new DragEventHandler(Dg_Drop);
            dg2.PreviewMouseLeftButtonDown += new MouseButtonEventHandler(DgSupp_PreviewMouseLeftButtonDown);
            dg2.Drop += new DragEventHandler(Dg_Drop);
        }

Then add all this after the MainWindow :

void Dg_Drop(object sender, DragEventArgs e)
        {
            int index = -1;
            DataGrid dg = new DataGrid();
            if (sender is DataGrid)
            {
                dg = (DataGrid)sender;
            }
            if (rowIndex < 0)
                return;
            if (dg.Name == "dg1")
            {
                index = this.GetCurrentRowIndexSupp(e.GetPosition);
            }
            if (dg.Name == "dg2")
            {
                index = this.GetCurrentRowIndexAdd(e.GetPosition);
            }
            if (index < 0)
                return;
            if (index == rowIndex)
                return;
            if (index == dg.Items.Count - 1)
            {
                MessageBox.Show("Last line can't moove");
                return;
            }
            if (dg.Name == "dg1")
            {
                if (dgName == "dg2")
                {
                    DataOfGrid changedProduct = yourlist2[rowIndex];
                    yourlist2.RemoveAt(rowIndex);
                    yourlist1.Insert(index, changedProduct);
                }
                else
                {
                    DataOfGrid changedProduct = yourlist1[rowIndex];
                    yourlist1.RemoveAt(rowIndex);
                    yourlist1.Insert(index, changedProduct);
                }
            }
            if (dg.Name == "dg2")
            {
                if (dgName == "dg1")
                {
                    DataOfGrid changedProduct = yourlist1[rowIndex];
                    yourlist1.RemoveAt(rowIndex);
                    yourlist2.Insert(index, changedProduct);
                }
                else
                {
                    DataOfGrid changedProduct = yourlist2[rowIndex];
                    yourlist2.RemoveAt(rowIndex);
                    yourlist2.Insert(index, changedProduct);
                }
            }
            dg1.ItemsSource = yourlist1;
            dg1.Items.Refresh();
            dg2.ItemsSource = yourlist2;
            dg2.Items.Refresh();
        }

        void DgSupp_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            DataGrid dg = new DataGrid();
            if (sender is DataGrid)
            {
                dg = (DataGrid)sender;
            }
            if (dg.Name == "dg1")
            {
                rowIndex = GetCurrentRowIndexSupp(e.GetPosition);
                dgName = dg.Name;
            }
            if (dg.Name == "dg2")
            {
                rowIndex = GetCurrentRowIndexAdd(e.GetPosition);
                dgName = dg.Name;
            }
            if (rowIndex < 0)
                return;
            dg.SelectedIndex = rowIndex;
            DataOfGrid selectedEmp = dg.Items[rowIndex] as DataOfGrid;
            if (selectedEmp == null)
                return;
            DragDropEffects dragdropeffects = DragDropEffects.Move;
            if (DragDrop.DoDragDrop(dg, selectedEmp, dragdropeffects)
                                != DragDropEffects.None)
            {
                dg.SelectedItem = selectedEmp;
            }
        }

        private bool GetMouseTargetRow(Visual theTarget, GetPosition position)
        {
            Rect rect = VisualTreeHelper.GetDescendantBounds(theTarget);
            Point point = position((IInputElement)theTarget);
            return rect.Contains(point);
        }

        private DataGridRow GetRowItemList1(int index)
        {
            if (dg1.ItemContainerGenerator.Status
                    != GeneratorStatus.ContainersGenerated)
                return null;
            return dg1.ItemContainerGenerator.ContainerFromIndex(index) as DataGridRow;
        }

        private DataGridRow GetRowItemList2(int index)
        {
            if (dg2.ItemContainerGenerator.Status
                    != GeneratorStatus.ContainersGenerated)
                return null;
            return dg2.ItemContainerGenerator.ContainerFromIndex(index) as DataGridRow;
        }

        private int GetCurrentRowIndexSupp(GetPosition pos)
        {
            int curIndex = -1;
            for (int i = 0; i < dg1.Items.Count; i++)
            {
                DataGridRow itm = GetRowItemList1(i);
                if (GetMouseTargetRow(itm, pos))
                {
                    curIndex = i;
                    break;
                }
            }
            return curIndex;
        }

        private int GetCurrentRowIndexAdd(GetPosition pos)
        {
            int curIndex = -1;
            for (int i = 0; i < dg2.Items.Count; i++)
            {
                DataGridRow itm = GetRowItemList2(i);
                if (GetMouseTargetRow(itm, pos))
                {
                    curIndex = i;
                    break;
                }
            }
            return curIndex;
        }

All you have to do is replace the "dg1" and "dg2" by the names of your Datagrid and the "yourlist1" and "yourlist2" by the lists that feed your Datagrid.

Please excuse me too for my English because I do not speak it at all, and I was inspired by Raj Kumar's article : https://www.c-sharpcorner.com/UploadFile/raj1979/drag-and-drop-datagrid-row-in-wpf/

Upvotes: 1

S. Gmiden
S. Gmiden

Reputation: 155

this a sample code (More Details here)

  1. Define MouseDown Event
  2. Define MouseMove Event to start DragAndDrop operation
  3. Define DragOver to test if drop allowed or not
  4. Define Drop event to do the drop operation

You can use the same event for the two datagrid

    private Point? _startPoint;

    private void dataGrid_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
    {
        _startPoint = e.GetPosition(null);
    }

    private void dataGrid_PreviewMouseMove(object sender, MouseEventArgs e)
    {
        // No drag operation
        if (_startPoint == null)
            return;

        var dg = sender as DataGrid;
        if (dg == null) return; 
        // Get the current mouse position
        Point mousePos = e.GetPosition(null);
        Vector diff = _startPoint.Value - mousePos;
        // test for the minimum displacement to begin the drag
        if (e.LeftButton == MouseButtonState.Pressed &&
            (Math.Abs(diff.X) > SystemParameters.MinimumHorizontalDragDistance ||
            Math.Abs(diff.Y) > SystemParameters.MinimumVerticalDragDistance))
        {

            // Get the dragged DataGridRow
            var DataGridRow=
                FindAnchestor<DataGridRow>((DependencyObject)e.OriginalSource);

            if (DataGridRow == null)
                return;
            // Find the data behind the DataGridRow
            var dataTodrop = (DataModel)dg.ItemContainerGenerator.
                ItemFromContainer(DataGridRow);

            if (dataTodrop == null) return;

            // Initialize the drag & drop operation
            var dataObj = new DataObject(dataTodrop);
            dataObj.SetData("DragSource", sender);
            DragDrop.DoDragDrop(dg, dataObj, DragDropEffects.Copy);
            _startPoint = null;
        }
    }

    private void dataGrid_PreviewMouseUp(object sender, MouseButtonEventArgs e)
    {
        _startPoint = null;
    }

    private void dataGrid_Drop(object sender, DragEventArgs e)
    {
        var dg = sender as DataGrid;
        if (dg == null) return;
        var dgSrc = e.Data.GetData("DragSource") as DataGrid;
        var data = e.Data.GetData(typeof(DataModel));
        if (dgSrc == null || data == null) return;
        // Implement move data here, depends on your implementation
        MoveDataFromSrcToDest(dgSrc, dg, data);
        // OR
        MoveDataFromSrcToDest(dgSrc.DataContext, dg.DataContext, data);
    }

    private void dataGrid_PreviewDragOver(object sender, DragEventArgs e)
    {
         // TO test if drop is allowed, to avoid drop 
         // if false e.Effects = DragDropEffects.None;
    }


    // Helper to search up the VisualTree
    private static T FindAnchestor<T>(DependencyObject current)
        where T : DependencyObject
    {
        do
        {
            if (current is T)
            {
                return (T)current;
            }
            current = VisualTreeHelper.GetParent(current);
        }
        while (current != null);
        return null;
    }

Hope this help :)

Upvotes: 5

Related Questions