简体   繁体   English

如何覆盖WPF DataGrid行为以实现拖放到外部应用程序?

[英]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. 我有一个WPF DataGrid,其定义如下。

<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. DataGrid绑定到一个可观察的集合。 The XAML column definitions have some columns hidden, some visible like this: XAML列定义隐藏了一些列,一些可见如下:

<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定义了一个鼠标右键按钮上下文菜单:

<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. 我正在考虑使用按“Alt键”和鼠标左键单击的组合来启动DragDrop操作。

For example, consider the "irregular" selection of cells in the DataGrid: 例如,考虑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? 1)我覆盖哪些事件,以便/鼠标左键单击不影响当前选定的单元格?

2) How do I determine whether the Left Mouse Button click is occurring within a region of selected cells? 2)如何确定鼠标左键单击是否在所选单元格的区域内发生? How do I handle the data piece? 我该如何处理数据?

3) Once I've determined the above, what is the next step? 3)一旦我确定了上述内容,下一步是什么? 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? 4)我需要在DataGrid上覆盖哪些事件(如果有的话)以使其工作?

Thanks 谢谢

the basic events to drag and drop are: events to drag and drop 拖放的基本事件是: 拖放事件

Specially the DragLeave and Drop to do what you want. 特别是DragLeave和Drop可以做你想要的。 Then you need to control (delete/add) the GridData property from your VM to search and move the values. 然后,您需要从VM控制(删除/添加)GridData属性以搜索和移动值。 I strongly recommend 3rd party like Telerik to do it. 我强烈建议像Telerik这样的第三方来做。

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. 在这里,你需要按下shift键来发出阻力信号。 This is needed to disambiguate the click and drag that is used in the DataGrid to select cells. 这需要消除DataGrid中用于选择单元格的单击和拖动的歧义。 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. 但您可能希望创建富文本或HTML或任意数量的其他格式。

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. 你不能强迫其他应用程序响应drop ...它必须正在倾听它。 So this example will work with Word and Excel. 因此,此示例将适用于Word和Excel。 It will not work with Notepad. 它不适用于记事本。

I believe all 4 items are satisfied: 我相信所有4项都满意:

  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. 使用DragDrop类实际实现拖放。
  4. Override preview mouse down. 覆盖预览鼠标。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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