我在使用DragDrop.DoDragDrop
时遇到了一些问题,它无法很好地与左键单击事件配合使用。
我的控件有几个链接,可以拖动或左键单击以访问。
我目前订阅了预览鼠标移动事件,如果按下左键,则会启动拖放事件。
在另一个回调中,我处理鼠标左键按下和抬起事件以检查是否进行了单击。有没有办法检查DragDrop是否实际上发生了拖放事件?
请参考此链接中关于WPF拖放的全面解释,并向下滚动到“检测拖放”一节。
以下代码在博客丢失时插入...
从 [http://msdn2.microsoft.com/en-us/library/aa289508(vs.71).aspx] 可以看出典型拖放操作的事件序列:
通过为源控件调用DoDragDrop方法来启动拖动。
DoDragDrop方法采用两个参数: data,指定要传递的数据;allowedEffects,指定允许哪些操作(复制和/或移动)。
将自动创建一个新的DataObject对象。 这又会引发GiveFeedback事件。在大多数情况下,您不需要担心GiveFeedback事件,但如果您想在拖动期间显示自定义鼠标指针,则可以在这里添加代码。
任何其AllowDrop属性设置为True的控件都是潜在的放置目标。AllowDrop属性可以在设计时在属性窗口中设置,也可以在Form_Load事件中以编程方式设置。
当鼠标经过每个控件时,该控件的DragEnter事件会被触发。GetDataPresent方法用于确保数据格式适合目标控件,Effect属性用于显示适当的鼠标指针。
如果用户在有效的放置目标上释放鼠标按钮,则触发DragDrop事件。在DragDrop事件处理程序中的代码从DataObject对象中提取数据,并在目标控件中显示它。
检测拖放
在调用DoDragDrop之前,我们必须检测源上的鼠标拖动操作......通常鼠标拖动由MouseLeftButtonDown + MouseMove(在MouseLeftButton抬起之前)组成。
因此,我们的拖放源控件需要订阅这两个事件:
void Window1_Loaded(object sender, RoutedEventArgs e)
{
this.DragSource.PreviewMouseLeftButtonDown += new MouseButtonEventHandler(DragSource_PreviewMouseLeftButtonDown);
this.DragSource.PreviewMouseMove += new MouseEventHandler(DragSource_PreviewMouseMove);
}
为了防止用户意外拖动而启动虚假的拖放操作,您可以使用
SystemParameters.MinimumHorizontalDragDistance 和 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部分中,我们将尝试为您介绍ListBox的HitTesting-这是我遇到的另一种常见情况。
一旦您有了要拖动的对象,就需要将您要发送的内容打包成一个DataObject,描述您正在传递的数据。 DataObject是一个包装器,用于将通用数据(使用可扩展格式标识)推入拖放操作中。只要源和目标都理解该格式,您就可以设置。因此,DataObject具有几个有趣的方法:
SetData (Type format, object data) ///格式是您传递的“格式”的当天情况(例如Formats.Text、Formats.Image等),您可以传递任何自定义类型。
GetDataPresent (Type format) ///是投放目标将用于查询和提取数据的方式。如果它是它可以处理的类型,它将调用GetData()并处理它。
这里没有太多有趣的东西...在示例中,我只将我的数据硬编码为字符串类型...这使得它更容易粘贴到外部容器中(例如Word,您可以用它来测试本文的这一部分)。我必须强调拖放应该是关于数据的......在拖放操作期间提供视觉反馈。
在调用DoDragDrop()之前,我们需要在提供反馈和d&d的“范围”方面做出一些“选择”。
我们是否想要在执行拖动操作时显示自定义光标?如果要使用光标,则应该是什么样式?
我们希望拖动多远?在应用程序内还是跨窗口应用程序?
最简单的情况:无自定义光标,并且我们希望它跨越应用程序拖动:
如果您不想要花哨的光标,那么您已经完成了!!您可以直接调用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;
}
注意:这段代码允许您在进程间拖放,它使用默认的操作系统反馈(例如+表示复制)。
有拖放事件的 Drag Over/Enter/Leave Attached。您可以在被拖曳的 UIElement 上订阅这些 (或一个) 事件的方法,以检查是否正在进行拖动。