【问题标题】:How do I override WPF DataGrid behaviour to implement Drag and Drop to an external application?如何覆盖 WPF DataGrid 行为以实现拖放到外部应用程序?
【发布时间】:2017-08-30 13:07:03
【问题描述】:

我有一个具有以下定义的 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 上覆盖哪些事件(如果有)才能使其正常工作?

谢谢

【问题讨论】:

    标签: c# wpf datagrid


    【解决方案1】:

    我相信这是你的完整答案。

        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 或任何数量的其他格式。

    您要放置的外部应用程序必须注册为放置目标。您不能强制其他应用程序响应丢弃...它必须在监听它。所以这个例子适用于 Word 和 Excel。它不适用于记事本。

    我相信所有 4 项都满意:

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

    【讨论】:

      【解决方案2】:

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

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

      【讨论】:

      • 谢谢,但我认为您不太明白我在问什么。我知道并且非常熟悉拖放及其相关事件。我试图在数据网格中选择一堆单元格,然后将它们拖到外部应用程序中。将其视为复制和粘贴的快捷方式。我没有在数据网格中删除或添加单元格。我在问如何覆盖标准 WPF 数据网格的行为/事件处理来实现这一点。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多