WPF 处理拖放以及左键单击
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/12802122/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
WPF handle drag and drop as well as left click
提问by bgura
I'm having some troubles getting DragDrop.DoDragDropto work along nicely with a left click event.
我在处理DragDrop.DoDragDrop左键单击事件时遇到了一些麻烦。
My control has several links which can either be dragged around or left clicked to visit.
我的控件有几个链接,可以拖动或左键单击访问。
I currently subscribe to the preview mouse move event which is where i launch the drag and drop event if the left mouse button is pressed.
我目前订阅了预览鼠标移动事件,如果按下鼠标左键,我将在该事件中启动拖放事件。
In another call back i handle the mouse left button down and up event to check for a click. Is there anyway to check if DragDrop actually had a drag drop event take place?
在另一个回调中,我处理鼠标左键按下和按下事件以检查点击。无论如何要检查 DragDrop 是否确实发生了拖放事件?
回答by Paul Zahra
See this link drag drop in wpf explained end to endand scroll down a little to the section "Detecting Drag & Drop"
请参阅wpf 中的此链接拖放解释端到端并向下滚动到“检测拖放”部分
Code inserted here encase the blog goes missing...
此处插入的代码使博客丢失...
From [http://msdn2.microsoft.com/en-us/library/aa289508(vs.71).aspx]Here is the sequence of events in a typical drag-and-drop operation:
来自 [ http://msdn2.microsoft.com/en-us/library/aa289508(vs.71).aspx]以下是典型拖放操作中的事件序列:
Dragging is initiated by calling the DoDragDrop method for the source control.
The DoDragDrop method takes two parameters: data, specifying the data to pass allowedEffects, specifying which operations (copying and/or moving) are allowed
A new DataObject object is automatically created. This in turn raises the GiveFeedback event. In most cases you do not need to worry about the GiveFeedback event, but if you wanted to display a custom mouse pointer during the drag, this is where you would add your code.
Any control with its AllowDrop property set to True is a potential drop target. The AllowDrop property can be set in the Properties window at design time, or programmatically in the Form_Load event.
As the mouse passes over each control, the DragEnter event for that control is raised. The GetDataPresent method is used to make sure that the format of the data is appropriate to the target control, and the Effect property is used to display the appropriate mouse pointer.
If the user releases the mouse button over a valid drop target, the DragDrop event is raised. Code in the DragDrop event handler extracts the data from the DataObject object and displays it in the target control.
拖动是通过调用源控件的 DoDragDrop 方法启动的。
DoDragDrop 方法有两个参数:data,指定要传递的数据 allowedEffects,指定允许哪些操作(复制和/或移动)
将自动创建一个新的 DataObject 对象。这反过来引发 GiveFeedback 事件。在大多数情况下,您无需担心 GiveFeedback 事件,但如果您想在拖动过程中显示自定义鼠标指针,您可以在此处添加代码。
任何其 AllowDrop 属性设置为 True 的控件都是潜在的放置目标。AllowDrop 属性可以在设计时在“属性”窗口中设置,也可以在 Form_Load 事件中以编程方式设置。
当鼠标经过每个控件时,会引发该控件的 DragEnter 事件。GetDataPresent 方法用于确保数据格式适合目标控件,Effect 属性用于显示合适的鼠标指针。
如果用户在有效的放置目标上释放鼠标按钮,则会引发 DragDrop 事件。DragDrop 事件处理程序中的代码从 DataObject 对象中提取数据并将其显示在目标控件中。
Detecting Drag & Drop
检测拖放
Before the DoDragDrop is called, we must detect a mouse Drag operation on the source... A mouse drag is usually a MouseLeftButtonDown + a MouseMove (before MouseLeftButton goes up).
在调用 DoDragDrop 之前,我们必须检测源上的鼠标拖动操作...鼠标拖动通常是一个 MouseLeftButtonDown + 一个 MouseMove(在 MouseLeftButton 上升之前)。
So, our drag & drop source control needs to subscribe to these two events:
所以,我们的拖放源控件需要订阅这两个事件:
void Window1_Loaded(object sender, RoutedEventArgs e)
{
this.DragSource.PreviewMouseLeftButtonDown += new MouseButtonEventHandler(DragSource_PreviewMouseLeftButtonDown);
this.DragSource.PreviewMouseMove += new MouseEventHandler(DragSource_PreviewMouseMove);
}
To prevent from starting a false drag & drop operation where the user accidentally drags, you can use
为了防止在用户不小心拖动的情况下启动错误的拖放操作,您可以使用
SystemParameters.MinimumHorizontalDragDistance and SystemParameters.MinimumVerticalDragDistance
SystemParameters.MinimumHorizontalDragDistance 和 SystemParameters.MinimumVerticalDragDistance
One way to do this is on MouseLeftButtonDown, record the starting position and onMouseMove check if the mouse has moved far enough..
一种方法是在 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);
}
Its a Drag .. now what?
它是一个拖动 .. 现在呢?
The data! You need to find out what is under the mouse when dragging. I will omit take the easy way out and assume that whoever is triggering the MouseMove is what I want to drag .. so look at MouseEventArgs.OriginalSource.. [or you could do some 2D HitTesting using VisualTreeHelper .. In Part3 of this write up will try to walk you through hit testing the listbox -which is the other common scenario I encounter-.
数据!拖动时需要找出鼠标下方的内容。我将省略采取简单的方法,并假设触发 MouseMove 的人就是我想要拖动的对象 .. 所以看看 MouseEventArgs.OriginalSource .. [或者你可以使用 VisualTreeHelper 做一些 2D HitTesting .. 在这篇文章的第 3 部分将尝试引导您完成对列表框的命中测试——这是我遇到的另一个常见场景——。
Once you have the object to drag, you will need to package what you are a sending into a DataObject that describes the data you are passing around. DataObject is a wrapper to push generic data (identified with extensible formats) into drag/drop.. As long as both the source and destination understand the format, you will be set. As such, DataObject has a couple interesting methods:
一旦有了要拖动的对象,您就需要将要发送的内容打包到一个 DataObject 中,该对象描述了您正在传递的数据。DataObject 是一个包装器,用于将通用数据(以可扩展格式标识)推送到拖/放中。只要源和目标都理解格式,您将被设置。因此,DataObject 有几个有趣的方法:
SetData ( Type format, object data ) /// format is the "format" of the day you are passing ( e.g. Formats.Text, Formats.Image, etc.. ) you can pass any custom types.
GetDataPresent ( Type format ) /// is what the drop target will use to inquire and extract the data .. if it is a type it can handle, it will call GetData () and handle it ..
SetData ( Type format, object data ) /// format 是您传递的当天的“格式”(例如 Formats.Text、Formats.Image 等。)您可以传递任何自定义类型。
GetDataPresent ( Type format ) /// 是放置目标将用来查询和提取数据的内容..如果是它可以处理的类型,它将调用GetData()并处理它..
Not much interesting stuff here.. In the sample I just hard-coded my data to be of type string... this makes it easier to paste into external containers (for example Word, which you can use to test this part of the write-up). I do have to stress that drag & dropping should be about the data ... Providing visual feedback during the drag & drop operation..
这里没有太多有趣的东西......在示例中,我只是将我的数据硬编码为字符串类型......这使得粘贴到外部容器(例如 Word,您可以使用它来测试写入的这一部分)变得更容易-向上)。我必须强调,拖放应该是关于数据......在拖放操作期间提供视觉反馈......
Before we call DoDragDrop () we have a few 'choices' to make around the feedback we want to provide and the 'scope' of the d&d.
在我们调用 DoDragDrop () 之前,我们需要围绕我们想要提供的反馈和 d&d 的“范围”做出一些“选择”。
Do we want a custom cursor to display while we are doing the Drag operation ? If we want a cursor, what should it be?
How far do we want to drag? within the app or across windows apps?
我们是否希望在执行拖动操作时显示自定义光标?如果我们想要一个游标,它应该是什么?
我们想拖多远?在应用程序内还是跨 Windows 应用程序?
Simplest scenario: No custom cursor and we want it to drag across apps:
最简单的场景:没有自定义光标,我们希望它跨应用程序拖动:
If you don't want a fancy cursor, you are done!! You can call DoDragDrop directly ...
如果你不想要一个花哨的光标,你就完成了!!可以直接调用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;
}
Note: this code allows you to drag & drop across processes, it uses the default operating system feedback ( e.g. + for copy)..
注意:此代码允许您跨进程拖放,它使用默认的操作系统反馈(例如 + 用于复制)。
回答by eran otzap
there are Drag Over/ Enter / Leave Attached events you can subscribe methods to these (or one) events on your dragged UIElement and see if the Dragging occurs .
有 Drag Over/Enter/Leave Attached 事件,您可以在拖动的 UIElement 上订阅这些(或一个)事件的方法,并查看是否发生拖动。

