WPF处理拖放以及左键单击

时间:2012-10-09 14:19:02

标签: c# wpf

我遇到一些麻烦,让 DragDrop.DoDragDrop 与左键单击事件很好地协同工作。

我的控件有几个链接,可以拖动或左键单击访问。

我目前订阅预览鼠标移动事件,如果按下鼠标左键,我将启动拖放事件。

在另一个回叫中,我处理鼠标左键向上和向上事件以检查点击。无论如何都要检查DragDrop是否确实发生了拖放事件?

2 个答案:

答案 0 :(得分:14)

请参阅this link drag drop in wpf explained end to end并稍微向下滚动到“检测拖放”一节

此处插入的代码包含了博客丢失...

From [http://msdn2.microsoft.com/en-us/library/aa289508(vs.71).aspx]以下是典型拖放操作中的事件序列:

  

通过调用源控件的DoDragDrop方法启动拖动。

     

DoDragDrop方法有两个参数:   数据,指定要传递allowedEffects的数据,指定允许哪些操作(复制和/或移动)

     

自动创建一个新的DataObject对象。   这反过来会引发GiveFeedback事件。在大多数情况下,您不必担心GiveFeedback事件,但如果您想在拖动过程中显示自定义鼠标指针,那么您可以在此处添加代码。

     

任何将AllowDrop属性设置为True的控件都是潜在的放置目标。 AllowDrop属性可以在设计时在“属性”窗口中设置,也可以在Form_Load事件中以编程方式设置。

     

当鼠标经过每个控件时,将引发该控件的DragEnter事件。 GetDataPresent方法用于确保数据的格式适合目标控件,Effect属性用于显示相应的鼠标指针。

     

如果用户在有效的放置目标上释放鼠标按钮,则会引发DragDrop事件。 DragDrop事件处理程序中的代码从DataObject对象中提取数据并将其显示在目标控件中。

检测拖动&降

在调用DoDragDrop之前,我们必须在源上检测鼠标拖动操作...鼠标拖动通常是MouseLeftButtonDown + MouseMove(在MouseLeftButton上升之前)。

所以,我们的拖累和drop source control需要订阅这两个事件:

void Window1_Loaded(object sender, RoutedEventArgs e)
{
    this.DragSource.PreviewMouseLeftButtonDown += new MouseButtonEventHandler(DragSource_PreviewMouseLeftButtonDown);
    this.DragSource.PreviewMouseMove += new MouseEventHandler(DragSource_PreviewMouseMove);
}

防止开始误拖&用户不小心拖动操作,可以使用

  

SystemParameters.MinimumHorizo​​ntalDragDistance和SystemParameters.MinimumVerticalDragDistance

一种方法是在MouseLeftButtonDown上,记录起始位置和onMouseMove检查鼠标是否移动得足够远..

void DragSource_PreviewMouseMove(object sender, MouseEventArgs e)
{
    if (e.LeftButton == MouseButtonState.Pressed && !IsDragging)
    {
        Point position = e.GetPosition(null);

        if (Math.Abs(position.X - _startPoint.X) > SystemParameters.MinimumHorizontalDragDistance ||
                Math.Abs(position.Y - _startPoint.Y) > SystemParameters.MinimumVerticalDragDistance)
        {
            StartDrag(e); 

        }
    }   
}

void DragSource_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
    _startPoint = e.GetPosition(null);
}

它是一个拖动..现在是什么?

数据!您需要在拖动时找出鼠标下方的内容。 我将省略简单的方法并假设无论是谁触发MouseMove都是我想要拖动的..所以看看MouseEventArgs.OriginalSource .. [或者你可以使用VisualTreeHelper做一些2D HitTesting ..在这篇文章的第3部分中将尝试引导您完成对列表框的测试 - 这是我遇到的另一种常见情况 - 。

一旦有了要拖动的对象,就需要将发送的内容打包到DataObject中,该DataObject描述您传递的数据。 DataObject是一个包装器,用于将通用数据(用可扩展格式标识)推送到拖放中。只要源和目标都理解格式,就会设置。因此,DataObject有几个有趣的方法:

  

SetData(类型格式,对象数据)///格式是您传递的日期的“格式”(例如Formats.Text,Formats.Image等),您可以传递任何自定义类型。

     

GetDataPresent(类型格式)///是放置目标用于查询和提取数据的内容..如果它是一个可以处理的类型,它将调用GetData()并处理它..

这里没什么有趣的东西..在示例中我只是将我的数据硬编码为字符串类型...这使得更容易粘贴到外部容器中(例如Word,您可以使用它来测试此部分的写作)。我不得不强调拖累和放大丢弃应该是关于数据... 在拖曳期间提供视觉反馈。放下操作..

在我们调用DoDragDrop()之前,我们有一些“选择”来围绕我们想要提供的反馈以及d& d的“范围”。

  

我们是否希望在执行拖动操作时显示自定义光标?如果我们想要一个光标,它应该是什么?

     

我们想拖多远?在应用程序内或跨Windows应用程序?

最简单的场景:没有自定义光标,我们希望它跨应用程序拖动:

如果您不想要花哨的光标,那么您就完成了!您可以直接致电DoDragDrop ......

private void StartDrag(MouseEventArgs e)
{
    IsDragging = true;
    DataObject data = new DataObject(System.Windows.DataFormats.Text.ToString(), "abcd");
    DragDropEffects de = DragDrop.DoDragDrop(this.DragSource, data, DragDropEffects.Move);
    IsDragging = false;
}

注意:此代码允许您拖放跨进程,它使用默认的操作系统反馈(例如+用于复制)..

答案 1 :(得分:0)

有Drag Over / Enter / Leave Attached事件 您可以在拖动的UIElement上订阅这些(或一个)事件的方法,看看是否发生了拖动。