简体   繁体   中英

How do I override WPF DataGrid behaviour to implement Drag and Drop to an external application?

I have a WPF DataGrid with the following definition.

<DataGrid Name="DataGridFoo"
  AutoGenerateColumns="False"
  ItemsSource="{Binding GridData}"
  IsReadOnly="True"
  SelectionMode="Extended"
  SelectionUnit="CellOrRowHeader">

This allows me to have the user selected a "region" of cells. The DataGrid is bound to an observable collection. The XAML column definitions have some columns hidden, some visible like this:

<DataGridTextColumn Binding="{Binding InvoiceID}"
   Header="Invoice ID"
   Visibility="Hidden"
   Width="Auto"/>                
<DataGridTextColumn Binding="{Binding InvoiceNumber}"
   Header="Invoice Number"
   Visibility="Visible"
   Width="Auto"/>
<DataGridTextColumn 
   Binding="{Binding InvoiceDate, StringFormat=\{0:MM/dd/yy\}}"
   Header="Invoice Date"
   Visibility="Visible"
   Width="Auto"/>

I also have a Right Mouse Button context menu defined for the DataGrid:

<DataGrid.ContextMenu>
  <ContextMenu FontSize="16"  Background="#FFE6E9EC">
    <MenuItem Header="Contact" Click="Contact_Click" />
    <Separator  />
    <MenuItem Header="Copy" Command="Copy" />
  </ContextMenu>
</DataGrid.ContextMenu>

I would like to be able to Click, Drag and Drop a copy of the currently selected cells into an external application. I was thinking of using the combination of pressing the "Alt Key" and Left Mouse Button click to initiate the DragDrop operation.

For example, consider the "irregular" selection of cells in the DataGrid:

在此输入图像描述

I am unclear on how to proceed and have several questions regarding this:

1) What events do I override so that the /Left Mouse click do not affect the currently selected cells?

2) How do I determine whether the Left Mouse Button click is occurring within a region of selected cells? How do I handle the data piece?

3) Once I've determined the above, what is the next step? Do copy data into the clipboard for use on the external drop?

4) What events (if any) do I need to override on the DataGrid in order for this to work?

Thanks

the basic events to drag and drop are: events to drag and drop

Specially the DragLeave and Drop to do what you want. Then you need to control (delete/add) the GridData property from your VM to search and move the values. I strongly recommend 3rd party like Telerik to do it.

Here is your complete answer I believe.

    private void dataGridMaster_PreviewMouseDown(object sender, MouseButtonEventArgs e)
    {
        if(Keyboard.IsKeyDown(Key.LeftShift) || Keyboard.IsKeyDown(Key.RightShift) & e.ChangedButton == MouseButton.Left)
        {
            DataGrid grid = e.Source as DataGrid;
            DataGridCell cell = GetParent<DataGridCell>(e.OriginalSource as DependencyObject);
            if(grid != null && cell != null && cell.IsSelected)
            {
                e.Handled = true;
                StartDragAndDrop(grid);
            }
        }
    }

    private T GetParent<T>(DependencyObject d) where T:class
    {
        while (d != null && !(d is T))
        {
            d = VisualTreeHelper.GetParent(d);
        }
        return d as T;

    }

    private void StartDragAndDrop(DataGrid grid)
    {
        StringBuilder sb = new StringBuilder();
        DataRow row = null;
        foreach(DataGridCellInfo ci in grid.SelectedCells)
        {
            DataRowView drv = ci.Item as DataRowView;
            string column = ci.Column.Header as string;
            if(drv != null && column != null)
            {
                if(drv.Row != row && row != null)
                {
                    sb.Length--;
                    sb.AppendLine();
                    row = drv.Row;
                }
                else if(row == null)
                {
                    row = drv.Row;
                }
                sb.Append(drv[column].ToString() + "\t");
            }
        }
        if (sb.Length > 0)
        {
            sb.Length--;
            sb.AppendLine();
        }
        DragDrop.DoDragDrop(grid, sb.ToString(), DragDropEffects.Copy);
    }

Here you need to have the shift key down to signal the drag. This is needed to disambiguate the click and drag that is used in the DataGrid to select cells. You might use some other mechanism such as context menu item.

The clipboard is key to any drag and drop operation. What you are doing is putting data on the clipboard in various formats that the target of the drop will recognize. In this example only plain text is used. But you might want to create rich text or HTML or any number of other formats.

The external application you are dropping on must be registered as a drop target. You cannot force the other app to respond to the drop...it must be listening for it. So this example will work with Word and Excel. It will not work with Notepad.

I believe all 4 items are satisfied:

  1. Override the preview mouse down event.
  2. The original source of the mouse event comes from the data grid cell. If the cell is selected then you are within the block of cells that is selected.
  3. For the selected cells, gather the data from the bindings and organize into a grid. As a baseline use plain text but optionally add other formats as well. Use the DragDrop class to actually implement the drag and drop.
  4. Override preview mouse down.

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