拖放:如何识别目标项条目

本文关键字:目标 识别 何识别 拖放 | 更新日期: 2023-09-27 18:06:30

我成功实现了两个DataGrids之间的拖放,即目标DataGrid知道源DataGrid的哪些条目被选中,并可以使用它们进行进一步处理。

现在我想确定目标DataGrid的入口,鼠标已经放置在那里。这是可能的吗?如果是,我该如何实现?

低于我的目标DataGrid代码:

void TargetList_Drop(object sender, DragEventArgs e)
{
  var mySourceRecords =
    e.Data.GetData(typeof(List<MySourceRecord>))
    as List<MySourceRecord>;
  // Process selected vehicle variants
  ... mySourceRecords should be processed here with the target DataGrid record ...
}

拖放:如何识别目标项条目

您可以使用VisualTreeHelper.HitTest执行命中测试

Point targetPoint = e.GetPosition(DataGrid1);
HitTestResult result = VisualTreeHelper.HitTest(DataGrid1, targetPoint);
DependencyObject dropTarget = result.VisualHit;

您可以使用InputHitTest在datagrid上执行命中测试,以确定掉落的位置

Point targetPoint = e.GetPosition(DataGrid1);
IInputElement dropTarget = DataGrid1.InputHitTest(targetPoint);
在这些方法之后的

dropTarget将是放置的位置。现在您可以通过几个方法来识别目标。

通过查找数据上下文(如果元素是frameworkelement)或通过查找适当的父元素的数据上下文。

查看您的代码,似乎目标应该是发送方,这取决于您如何设置拖放。即:

    void TargetList_Drop(object sender, DragEventArgs e)
    {
        var target = (FrameworkElement) sender;
    }

但是,您可能订阅了数据网格上的drop,而不是它的可视化子元素,因此上述内容可能不适合您。

下面附加的行为可能有助于解决您的问题。我已经用了很多年了。您只需在可拖放的元素上设置IsDragSource,在可接受拖放的元素上设置IsDropTarget。我通常使用MVVM,所以我添加了一个DropCommand,以便它是视图模型来处理drop。

public static class DragAndDropManager
{
    #region IsDragSource Attached Property
    public static readonly DependencyProperty IsDragSourceProperty
        = DependencyProperty.RegisterAttached("IsDragSource",typeof(bool),typeof(DragAndDropManager),new PropertyMetadata(IsDragSourceChanged));
    public static void SetIsDragSource(DependencyObject d, bool value)
    {
        d.SetValue(IsDragSourceProperty, true);
    }
    public static bool GetIsDragSource(DependencyObject d)
    {
        return (bool)d.GetValue(IsDragSourceProperty);
    }
    private static void IsDragSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var element = d as FrameworkElement;
        if (element == null)
            return;
        element.PreviewMouseMove += OnPreviewMouseMove;
    }
    private static void OnPreviewMouseMove(object sender, MouseEventArgs args)
    {
        var element = (FrameworkElement)sender;
        var dragSource = args.OriginalSource as FrameworkElement;
        if (args.LeftButton != MouseButtonState.Pressed
            || dragSource == null
            || dragSource.DataContext == null)
            return;
        var dragData = new DataObject(dragSource.DataContext);
        DragDrop.DoDragDrop(element, dragData, DragDropEffects.Move);
    }
    #endregion
    #region IsDropTarget Attached Property
    public static readonly DependencyProperty IsDropTargetProperty
        = DependencyProperty.RegisterAttached("IsDropTarget",typeof(bool),typeof(DragAndDropManager),new PropertyMetadata(IsDropTargetChanged));
    public static void SetIsDropTarget(DependencyObject d, bool value)
    {
        d.SetValue(IsDropTargetProperty, true);
    }
    public static bool GetIsDropTarget(DependencyObject d)
    {
        return (bool)d.GetValue(IsDropTargetProperty);
    }
    private static void IsDropTargetChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var element = d as FrameworkElement;
        if (element == null)
            return;
        element.AllowDrop = true;
        element.DragOver += OnDragOver;
        element.Drop += OnDrop;
    }
    private static void OnDragOver(object sender, DragEventArgs e)
    {
        if (e.Data == null || e.Handled)
        {
            e.Effects = DragDropEffects.None;
            return;
        }
        var element = (FrameworkElement)sender;
        var command = GetDropCommand(element);
        if (command == null)
            return;
        var dataFormats = e.Data.GetFormats();
        if (dataFormats==null)
            return;
        var dragAndDropInfo = new DragAndDropInfo(element.DataContext,
                            e.Data.GetData(dataFormats.FirstOrDefault()));
        var canDrop = dragAndDropInfo.DroppedItem != dragAndDropInfo.SourceItem
                        && command.CanExecute(dragAndDropInfo);
        e.Handled = true;
        e.Effects = canDrop
                    ? e.Effects = DragDropEffects.All
                    : DragDropEffects.None;
    }
    private static void OnDrop(object sender, DragEventArgs e)
    {
        if (e.Data == null || e.Handled)
            return;
        var element = (FrameworkElement)sender;
        var command = GetDropCommand(element);
        if (command == null)
            return;
        var dataFormats = e.Data.GetFormats();
        if (dataFormats == null)
            return;
        var dragAndDropInfo = new DragAndDropInfo(element.DataContext,
                            e.Data.GetData(dataFormats.FirstOrDefault()));
        var canDrop = dragAndDropInfo.DroppedItem != dragAndDropInfo.SourceItem
                       && command.CanExecute(dragAndDropInfo);
        if (canDrop)
        {
            command.Execute(dragAndDropInfo);
        }
        e.Handled = true;
    }
    #endregion
    #region DropCommand Attached Property
    public static readonly DependencyProperty DropCommandProperty
        = DependencyProperty.RegisterAttached("DropCommand",typeof(ICommand),typeof(DragAndDropManager),new PropertyMetadata(DropCommandProperty));
    public static void SetDropCommand(DependencyObject d, ICommand value)
    {
        d.SetValue(DropCommandProperty, value);
    }
    public static ICommand GetDropCommand(DependencyObject d)
    {
        return (ICommand)d.GetValue(DropCommandProperty);
    }
    #endregion
}

public class DragAndDropInfo
{
    public object SourceItem { get; private set; }
    public object DroppedItem { get; private set; }
    public DragAndDropInfo(object sourceItem, object droppedItem)
    {
        SourceItem = sourceItem;
        DroppedItem = droppedItem;
    }
}

}

下面是TreeView示例的XAML示例。在你的例子中,你可以在行展示器上做类似的事情,等等
<TreeView
  Behaviors:DragAndDropManager.IsDropTarget="true"
  Behaviors:DragAndDropManager.DropCommand="{Binding DropCommand}">
  <TreeView.Resources>
    <Style TargetType="TreeViewItem">
      <Style.Setters>/>
        <Setter Property="Behaviors:DragAndDropManager.IsDragSource" Value="true"/>
        <Setter Property="Behaviors:DragAndDropManager.IsDropTarget" Value="true"/>
        <Setter Property="Behaviors:DragAndDropManager.DropCommand" Value="{Binding DropCommand}"/>
      </Style.Setters>
    </Style>
  </TreeView.Resources>
</TreeView>