拖放概述

更新:2011 年 4 月

本主题概述 Windows Presentation Foundation (WPF) 应用程序中对拖放的支持。 拖放通常指一种数据传输方法,包括一系列操作:使用鼠标(或其他一些指针设备)选择一个或多个对象,将这些对象拖到user interface (UI) 中的一些期望放置目标上,然后放下它们。

本主题包括下列各节。

  • WPF 中对拖放的支持
  • 数据传输
  • 拖放事件
  • 实现拖放
  • 拖放示例
  • 相关主题

WPF 中对拖放的支持

拖放操作通常涉及两方:拖动源(从中拖动被拖动对象)和放置目标(接收被拖动对象)。 拖动源和放置目标可以是同一应用程序或不同应用程序中的 UI 元素。

可使用拖放操作的对象类型和数量完全是任意的。 例如,文件、文件夹和内容选择就是一些可通过拖放操作处理的常见对象。

拖放操作期间执行的特定操作是特定于应用程序的,通常由上下文确定。 例如,默认情况下,如果将所选的文件从一个文件夹拖动到同一存储设备上的另一个文件夹,则会移动文件,而如果将文件从Universal Naming Convention (UNC) 共享区拖动到本地文件夹,则会复制这些文件。

WPF 提供的拖放功能设计得非常灵活且可自定义,可支持各种拖放情形。 拖放支持在一个应用程序中或在不同的应用程序间操作对象。 还完全支持在 WPF 应用程序与其他 Windows 应用程序之间的拖放。

在 WPF 中,任何 UIElementContentElement 都可以参与拖放。 DragDrop 类中定义了拖放操作所需的事件和方法。 UIElementContentElement 类包含 DragDrop 附加事件的别名,以便在将 UIElementContentElement 作为基元素进行继承时,这些事件会出现在类成员列表中。 附加到这些事件的事件处理程序将附加到基础 DragDrop 附加事件,并接收同一事件数据实例。 有关更多信息,请参见 UIElement.Drop 事件。

安全说明安全说明

OLE 拖放在 Internet 区域中不起作用。

数据传输

拖放属于较常见的数据传输范畴。 数据传输包括拖放和复制并粘贴操作。 拖放操作类似于使用系统剪贴板将数据从一个对象或应用程序传输到另一个对象或应用程序的复制并粘贴或剪切并粘贴操作。 这两种操作类型都需要:

  • 提供数据的源对象。

  • 用于临时存储传输数据的途径。

  • 接收数据的目标对象。

在复制并粘贴操作中,系统剪贴板用于临时存储传输数据;在拖放操作中,DataObject 用于存储数据。 从概念上而言,一个数据对象由一对或多对包含实际数据的 Object 和对应数据格式标识符组成。

拖动源通过调用静态 DragDrop.DoDragDrop 方法并将传输数据传递给该方法来启动拖放操作。 如果需要,DoDragDrop 方法会自动将数据包装在 DataObject 中。 若要更好地控制数据格式,您可以先将数据包装在 DataObject 中,然后再将其传递给 DoDragDrop 方法。 放置目标负责从 DataObject 中提取数据。 有关如何处理数据对象的更多信息,请参见数据和数据对象

拖放操作的源和目标是 UI 元素;但是,实际传输的数据通常没有可视化表示形式。 您可以编写代码来提供所拖动数据的可视化表示形式(如在 Windows 资源管理器中拖动文件时发生)。 默认情况下,向用户提供反馈的方式是更改光标,以表示拖放操作会对数据产生的效果(例如是移动还是复制数据)。

拖放效果

拖放操作可以对传输数据产生不同的效果。 例如,可以复制数据,也可以移动数据。 WPF 定义了一个 DragDropEffects 枚举,可以使用该枚举指定拖放操作的效果。 在拖动源中,可以在 DoDragDrop 方法中指定源允许的效果。 在放置目标中,可以在 DragEventArgs 类的 Effects 属性中指定目标的预期效果。 当放置目标在 DragOver 事件中指定其预期效果时,该信息会在 GiveFeedback 事件中传回拖动源。 拖动源使用此信息通知用户放置目标对数据的预期效果。 当放置数据时,放置目标在 Drop 事件中指定其实际效果。 该信息作为 DoDragDrop 方法的返回值传回拖动源。 如果放置目标返回的效果不在 allowedEffects 的拖动源列表中,则会取消拖放操作,不进行任何数据传输。

请务必记住,在 WPF 中,DragDropEffects 值仅用于在拖动源和放置目标间提供关于拖放操作效果的通信。 拖放操作的实际效果取决于您在应用程序中编写的相应代码。

例如,放置目标可以指定在其上放置数据的效果是移动数据。 但是,若要移动数据,必须将数据添加到目标元素中并从源元素中移除。 源元素可能指示它允许移动数据,但如果您未提供用于从源元素移除数据的代码,则最终结果将是复制数据,而不会进行移动。

拖放事件

拖放操作支持事件驱动模型。 拖动源和放置目标都使用一组标准事件来处理拖放操作。 下表汇总了标准拖放事件。 这些是 DragDrop 类的附加事件。 有关附加事件的更多信息,请参见附加事件概述

拖动源事件

Event

摘要

[ E:System.Windows.DragDrop.GiveFeedback ]

此事件在拖放操作过程中持续发生,使放置源可以向用户提供反馈信息。 提供此反馈的方法通常是更改鼠标指针的外观,以指示放置目标允许的效果。 这是一个冒泡事件。

[ E:System.Windows.DragDrop.QueryContinueDrag ]

当拖放操作期间键盘或鼠标按钮状态更改时发生此事件,它使放置源能够根据键/按钮状态取消拖放操作。 这是一个冒泡事件。

[ E:System.Windows.DragDrop.PreviewGiveFeedback ]

GiveFeedback 的隧道版本。

[ E:System.Windows.DragDrop.PreviewQueryContinueDrag ]

QueryContinueDrag 的隧道版本。

放置目标事件

Event

摘要

[ E:System.Windows.DragDrop.DragEnter ]

将对象拖至放置目标的边框内时发生此事件。 这是一个冒泡事件。

[ E:System.Windows.DragDrop.DragLeave ]

将对象拖出放置目标的边框时发生此事件。 这是一个冒泡事件。

[ E:System.Windows.DragDrop.DragOver ]

在放置目标的边框内拖动(移动)对象时会持续发生此事件。 这是一个冒泡事件。

[ E:System.Windows.DragDrop.Drop ]

将对象放到放置目标上时发生此事件。 这是一个冒泡事件。

[ E:System.Windows.DragDrop.PreviewDragEnter ]

DragEnter 的隧道版本。

[ E:System.Windows.DragDrop.PreviewDragLeave ]

DragLeave 的隧道版本。

[ E:System.Windows.DragDrop.PreviewDragOver ]

DragOver 的隧道版本。

[ E:System.Windows.DragDrop.PreviewDrop ]

Drop 的隧道版本。

若要为对象的实例处理拖放事件,请为前面表中列出的事件添加处理程序。 若要在类级别处理拖放事件,请重写对应的虚拟 On*Event 和 On*PreviewEvent 方法。 有关更多信息,请参见按控件基类进行的路由事件类处理

实现拖放

UI 元素可以作为拖动源、放置目标或同时作为拖动源和放置目标。 若要实现基本拖放,请编写代码来启动拖放操作和处理放置的数据。 您可通过处理可选的拖放事件来进一步增强拖放体验。

为了实现基本拖放,您将完成以下任务:

  • 标识将作为拖动源的元素。 拖动源可以是 UIElementContentElement

  • 对将启动拖放操作的拖动源创建一个事件处理程序。 该事件通常为 MouseMove 事件。

  • 在拖动源事件处理程序中,调用 DoDragDrop 方法以启动拖放操作。 在 DoDragDrop 调用中,指定拖动源、要传输的数据以及允许的效果。

  • 标识将作为放置目标的元素。 放置目标可以是 UIElementContentElement

  • 对于放置目标,将 AllowDrop 属性设置为 true。

  • 在放置目标中,创建一个 Drop 事件处理程序来处理放置的数据。

  • Drop 事件处理程序中,使用 GetDataPresentGetData 方法从 DragEventArgs 提取数据。

  • Drop 事件处理程序中,使用这些数据执行所需的拖放操作。

可以通过创建自定义 DataObject 以及处理可选拖动源和放置目标事件来增强拖放实现,如下面的任务所示:

  • 若要传输自定义数据或多个数据项,请创建一个 DataObject 以传递给 DoDragDrop 方法。

  • 若要在拖动过程中执行其他操作,请处理放置目标的 DragEnterDragEnterDragEnter 事件。

  • 若要更改鼠标指针的外观,请处理拖动源的 GiveFeedback 事件。

  • 若要更改拖放操作的取消方式,请处理拖动源的 QueryContinueDrag 事件。

拖放示例

本节描述如何为 Ellipse 元素实现拖放。 Ellipse 既是拖动源又是放置目标。 传输的数据是椭圆的 Fill 属性的字符串表示形式。 下面的 XAML 演示 Ellipse 元素及其处理的与拖放有关的事件。 有关如何实现拖放的完整步骤,请参见演练:对用户控件启用拖放功能

使元素作为拖动源

作为拖动源的对象负责以下任务:

  • 标识进行拖动的时间。

  • 启动拖放操作。

  • 标识要传输的数据。

  • 指定允许拖放操作对传输数据产生的效果。

拖动源还可以就允许的操作(移动、复制、无)向用户提供反馈,并可以基于其他用户输入(如拖动过程中按 Esc 键)取消拖放操作。

由应用程序负责确定进行拖动的时间,然后通过调用 DoDragDrop 方法来启动拖放操作。 通常,这是在按下鼠标按钮期间,在要拖动的元素上发生 MouseMove 事件时。 下面的示例演示如何从 Ellipse 元素的 MouseMove 事件处理程序启动拖放操作,以将该元素作为拖动源。 传输的数据是椭圆的 Fill 属性的字符串表示形式。

MouseMove 事件处理程序中,调用 DoDragDrop 方法以启动拖放操作。 DoDragDrop 方法采用三个参数:

  • dragSource – 对作为传输数据的源的依赖项对象的引用;这通常是 MouseMove 事件的源。

  • data - 包含传输数据的对象,包装在 DataObject 中。

  • allowedEffects - DragDropEffects 枚举值之一,该值指定拖放操作的允许效果。

任何可序列化对象都可在 data 参数中传递。 如果数据尚未包装在 DataObject 中,则会自动包装在新的 DataObject 中。 若要传输多个数据项,必须自己创建 DataObject,并将其传递给 DoDragDrop 方法。 有关更多信息,请参见数据和数据对象

allowedEffects 参数用于指定拖动源允许放置目标对传输数据执行的操作。 拖动源的常见值有 CopyMoveAll

注意注意

放置目标也能够指定它预期以何种效果来响应放置的数据。例如,如果放置目标无法识别要放置的数据类型,则可以通过将其允许的效果设置为 None 来拒绝这些数据。它通常是在其 DragOver 事件处理程序中实现此功能。

拖动源可以选择处理 GiveFeedbackQueryContinueDrag 事件。 这些事件具有默认处理程序,除非将事件标记为已处理,否则会使用这些处理程序。 除非您有更改其默认行为的特定需求,否则通常会忽略这些事件。

在对拖动源进行拖动期间,会持续引发 GiveFeedback 事件。 此事件的默认处理程序会检查拖动源是否位于有效的放置目标上。 如果是,则检查放置目标的允许效果。 然后向最终用户提供关于允许的放置效果的反馈。 这通常是通过将鼠标光标更改为禁止放置、复制或移动光标来实现的。 仅当您需要使用自定义光标向用户提供反馈时,才应处理此事件。 如果处理此事件,请务必将其标记为已处理,以便默认处理程序不会重写您的处理程序。

在对拖动源进行拖动期间,会持续引发 QueryContinueDrag 事件。 您可以处理此事件,以根据 Esc、Shift、Ctrl 和 Alt 键的状态以及鼠标按钮的状态来确定结束拖放操作的操作。 此事件的默认处理程序会在按 Esc 键时取消拖放操作,在释放鼠标按钮时放置数据。

警告说明警告

这些事件在拖放操作过程中持续引发。因此,在事件处理程序中应避免使用消耗大量资源的任务。例如,在每次引发 GiveFeedback 事件时使用缓存的光标而不是创建新光标。

使元素作为放置目标

作为放置目标的对象负责以下任务:

  • 指定它是有效的放置目标。

  • 在拖动源拖动到目标上时响应拖动源。

  • 检查传输的数据是否采用它可以接收的格式。

  • 处理放置的数据。

若要指定某个元素作为放置目标,请将其 AllowDrop 属性设置为 true。 随后会对该元素引发放置目标事件,以便您可以处理这些事件。 在拖放操作过程中,会在放置目标上发生以下事件序列:

  1. [ E:System.Windows.DragDrop.DragEnter ]

  2. [ E:System.Windows.DragDrop.DragOver ]

  3. DragLeaveDrop

将数据拖至放置目标的边框内时发生 DragEnter 事件。 通常处理此事件以提供拖放操作的效果预览(如果适用于您的应用程序)。 请勿在 DragEnter 事件中设置 DragEventArgs.Effects 属性,因为在 DragOver 事件中会覆盖该属性。

下面的示例演示 Ellipse 元素的 DragEnter 事件处理程序。 此代码通过保存当前 Fill 画笔来预览拖放操作的效果。 随后使用 GetDataPresent 方法检查拖动到椭圆上方的 DataObject 是否包含可以转换为 Brush 的字符串数据。 如果是,则使用 GetData 方法提取数据。 这些数据随后转换为 Brush 并应用于椭圆。 更改在 DragLeave 事件处理程序中进行还原。 如果数据无法转换为 Brush,则不执行任何操作。

将数据拖至放置目标上方时会连续发生 DragOver 事件。 此事件与拖动源上的 GiveFeedback 事件配对。 在 DragOver 事件处理程序中,通常使用 GetDataPresentGetData 方法检查传输的数据是否采用放置目标可以处理的格式。 还可以检查是否按下了任何修改键,这通常指示用户是要执行移动还是复制操作。 执行完这些检查后,可设置 DragEventArgs.Effects 属性以通知拖动源放置数据将产生何种效果。 拖动源在 GiveFeedback 事件参数中接收此信息,并且可以设置相应的光标来向用户提供反馈。

下面的示例演示 Ellipse 元素的 DragOver 事件处理程序。 此代码检查拖动到椭圆上方的 DataObject 是否包含可以转换为 Brush 的字符串数据。 如果是,则此代码会将 DragEventArgs.Effects 属性设置为 Copy。 这会向拖动源指示,可以将数据复制到椭圆。 如果数据无法转换为 Brush,则 DragEventArgs.Effects 属性会设置为 None。 这会向拖动源指示,椭圆不是这些数据的有效放置目标。

将数据拖出目标边框而不放置时发生 DragLeave 事件。 处理此事件可撤消在 DragEnter 事件处理程序中执行的所有操作。

下面的示例演示 Ellipse 元素的 DragLeave 事件处理程序。 此代码通过将保存的 Brush 应用于椭圆,来撤消在 DragEnter 事件处理程序中执行的预览。

将数据放置在放置目标上时会发生 Drop 事件;这通常是在释放鼠标按钮时发生。 在 Drop 事件处理程序中,使用 GetData 方法从 DataObject 中提取传输的数据并执行应用程序所需的所有数据处理。 Drop 事件结束拖放操作。

下面的示例演示 Ellipse 元素的 Drop 事件处理程序。 此代码应用拖放操作的效果,与 DragEnter 事件处理程序中的代码相似。 此代码检查拖动到椭圆上方的 DataObject 是否包含可以转换为 Brush 的字符串数据。 如果是,则对椭圆应用 Brush。 如果数据无法转换为 Brush,则不执行任何操作。

请参见

参考

Clipboard

其他资源

演练:对用户控件启用拖放功能

拖放帮助主题

拖放

修订记录

日期

修订记录

原因

2011 年 4 月

更新了主题。

客户反馈