繁体   English   中英

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

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

我有一个WPF DataGrid,其定义如下。

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

这允许我让用户选择单元格的“区域”。 DataGrid绑定到一个可观察的集合。 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"/>

我还为DataGrid定义了一个鼠标右键按钮上下文菜单:

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

我希望能够将当前选定单元格的副本单击,拖放到外部应用程序中。 我正在考虑使用按“Alt键”和鼠标左键单击的组合来启动DragDrop操作。

例如,考虑DataGrid中“不规则”的单元格选择:

在此输入图像描述

我不清楚如何处理并对此有几个问题:

1)我覆盖哪些事件,以便/鼠标左键单击不影响当前选定的单元格?

2)如何确定鼠标左键单击是否在所选单元格的区域内发生? 我该如何处理数据?

3)一旦我确定了上述内容,下一步是什么? 是否将数据复制到剪贴板以便在外部删除中使用?

4)我需要在DataGrid上覆盖哪些事件(如果有的话)以使其工作?

谢谢

拖放的基本事件是: 拖放事件

特别是DragLeave和Drop可以做你想要的。 然后,您需要从VM控制(删除/添加)GridData属性以搜索和移动值。 我强烈建议像Telerik这样的第三方来做。

以下是我相信的完整答案。

    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);
    }

在这里,你需要按下shift键来发出阻力信号。 这需要消除DataGrid中用于选择单元格的单击和拖动的歧义。 您可以使用其他一些机制,例如上下文菜单项。

剪贴板是任何拖放操作的关键。 您正在做的是将数据放在剪贴板上,以丢弃目标识别的各种格式。 在此示例中,仅使用纯文本。 但您可能希望创建富文本或HTML或任意数量的其他格式。

您要使用的外部应用程序必须注册为放置目标。 你不能强迫其他应用程序响应drop ...它必须正在倾听它。 因此,此示例将适用于Word和Excel。 它不适用于记事本。

我相信所有4项都满意:

  1. 覆盖预览鼠标按下事件。
  2. 鼠标事件的原始来源来自数据网格单元。 如果选择了单元格,则表示您位于所选单元格块内。
  3. 对于选定的单元格,从绑定中收集数据并组织到网格中。 作为基线使用纯文本,但也可以选择添加其他格式。 使用DragDrop类实际实现拖放。
  4. 覆盖预览鼠标。

暂无
暂无

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

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