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

时间:2014-06-04 09:12:02

标签: c# wpf datagrid drag-and-drop

我成功实现了两个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 ...
}

2 个答案:

答案 0 :(得分:0)

您可以使用VisualTreeHelper.HitTest

执行点击测试
Point targetPoint = e.GetPosition(DataGrid1);
HitTestResult result = VisualTreeHelper.HitTest(DataGrid1, targetPoint);
DependencyObject dropTarget = result.VisualHit;

您可以使用InputHitTest对数据网格执行匹配测试,以确定丢弃的位置

Point targetPoint = e.GetPosition(DataGrid1);
IInputElement dropTarget = DataGrid1.InputHitTest(targetPoint);

在这些方法之后,dropTarget将成为放置的那个。现在你可以通过几种方法识别目标。

通过查找datacontext(如果元素是frameworkelement)或找到适当的父级datacontext。

答案 1 :(得分:0)

查看您的代码,目标应该是发件人,具体取决于您设置拖放的方式。那就是:

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

但是,您可能订阅了数据网格而不是视觉子网,因此上述内容可能对您无效。

以下附加行为可能有助于解决您的问题。我已经使用它多年了。您可以简单地在可拖动的元素上设置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;
    }
}

}

以下示例XAML用于TreeView示例。在你的情况下,你可以在行演示者等上做类似的事情

<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>