拖放概述
更新:2007 年 11 月
本主题概述 Windows Presentation Foundation (WPF) 应用程序中对拖放的支持。拖放通常指一种用户界面 (UI) 交互方法,包括一系列操作:使用鼠标(或其他一些指针设备)选择一个或多个对象,将这些对象拖到 UI 中的一些期望放置目标上,然后放下它们。
本主题包括下列各节。
- WPF 中对拖放的支持
- 数据和数据对象
- 拖放事件
- 处理数据对象
- 相关主题
WPF 中对拖放的支持
拖放操作通常涉及两方:拖动源(从中拖动被拖动对象)和放置目标(接收被拖动对象)。 拖动源和放置目标可以是同一应用程序,也可以是不同的应用程序。
可使用拖放操作的对象类型和数量完全是任意的;可通过拖放操作处理的一些较常见对象有:一个或多个文件或文件夹、内容选择等。 拖放操作期间执行的特定操作是特定于应用程序的,通常由上下文确定。 例如,默认情况下,如果将所选的文件从一个文件夹拖动到同一存储设备上的另一个文件夹,则会移动文件,而如果将文件从通用命名约定 (UNC) 共享区拖动到本地文件夹,则会复制这些文件。 WPF 提供的拖放功能设计得非常灵活且可自定义,可支持各种拖放情形。 拖放支持在一个应用程序中或在不同的应用程序间操作对象;还完全支持 WPF 应用程序与其他 Windows 应用程序之间的拖放。 拖放属于较常见的数据传输范畴;除拖放之外,数据传输还包括使用系统剪贴板进行复制和粘贴操作。
**安全说明:**OLE 拖放在 Internet 区域中不起作用。
数据和数据对象
在拖放操作中传输的数据存储在数据对象中。 概念上而言,数据对象包含一对或多对下列组件:
一个包含实际数据的 Object,
一个对应的数据格式标识符。
数据本身可以包含作为基本 Object 表示的任何内容。 对应的数据格式是提供有关数据格式的提示的字符串或 Type。数据对象支持承载多个数据-(数据格式) 对;这样,单一数据对象即可提供多种格式的数据。
所有数据对象都必须实现 IDataObject 接口,该接口提供以下标准方法集,以启用和便于数据传输。
方法 |
摘要 |
---|---|
检索指定数据格式的数据对象。 |
|
查看是否具有指定格式的数据,或者数据是否可以转换为指定格式。 |
|
返回一个格式列表,此数据对象中的数据以这些格式存储,或可以转换为这些格式。 |
|
在此数据对象中存储指定的数据。 |
WPF 提供 DataObject 类中的 IDataObject 的基本实现;对于许多常见数据传输方案,常用 DataObject 类已足够满足要求。
有关随 WPF 提供的预定义数据格式的信息,请参见 DataFormats 类参考主题。
数据对象通常包括在提取数据时将以一种格式存储的数据自动转换为另一种格式的功能,此功能称为自动转换。
当查询数据对象中的可用数据格式时,可以通过调用 GetFormats(Boolean) 或 GetDataPresent(String, Boolean) 方法并将 autoConvert 参数指定为 false 来从本机数据格式中筛选可自动转换的数据格式。 当使用 SetData(String, Object, Boolean) 方法将数据添加到数据对象中时,可以通过将 autoConvert 参数设置为 false 来禁止数据自动转换。
拖放事件
拖放操作支持事件驱动模型。 拖动源和放置目标都使用一组标准事件来处理拖放操作。 下表汇总了标准拖放事件。
拖动源事件
事件 |
摘要 |
---|---|
当启动拖放操作时发生此事件,它使放置目标将反馈信息发送回拖动源;拖动源通常使用此反馈来动态调整鼠标指针的外观,以便向用户提供反馈。 这是一个冒泡事件。 |
|
当拖放操作期间键盘或鼠标按钮状态更改时发生此事件,它使放置源能够根据键/按钮状态取消拖放操作。这是一个冒泡事件。 |
|
GiveFeedback 的隧道版本。 |
|
QueryContinueDrag 的隧道版本。 |
放置目标事件
事件 |
摘要 |
---|---|
将对象拖至放置目标的边框内时发生此事件。这是一个冒泡事件。 |
|
将对象拖出放置目标的边框时发生此事件。 这是一个冒泡事件。 |
|
在放置目标的边框内拖动(移动)对象时发生此事件。这是一个冒泡事件。 |
|
将对象放到放置目标上时发生此事件。 这是一个冒泡事件。 |
|
DragEnter 的隧道版本。 |
|
DragLeave 的隧道版本。 |
|
DragOver 的隧道版本。 |
|
Drop 的隧道版本。 |
处理数据对象
本节介绍创建和处理数据对象的常见技术。
使用 DataObject 构造函数
DataObject 类提供一些重载构造函数,以便于使用单一数据-(数据格式) 对来填充新的 DataObject 实例。
下面的示例代码新建一个数据对象,并利用重载构造函数之一 (DataObject(String, Object)),使用一个字符串和指定的数据格式初始化该数据对象。 在这种情况下,数据格式由一个字符串指定;DataFormats 类提供一组预定义的类型字符串。默认情况下允许存储数据的自动转换。
string stringData = "Some string data to store...";
string dataFormat = DataFormats.UnicodeText;
DataObject dataObject = new DataObject(dataFormat, stringData);
有关创建数据对象的更多代码示例,请参见如何:创建数据对象。
存储多种格式的数据
一个数据对象能够存储多种格式的数据。 与只提供一种数据格式相比较,在一个数据对象中策略性地使用多种数据格式可以使该数据对象供更多种放置目标使用。 请注意,一般而言,拖动源一定不知道潜在放置目标可使用的数据格式。
下面的示例演示如何使用 SetData(String, Object) 方法将数据以多种格式添加到数据对象中。
DataObject dataObject = new DataObject();
string sourceData = "Some string data to store...";
// Encode the source string into Unicode byte arrays.
byte[] unicodeText = Encoding.Unicode.GetBytes(sourceData); // UTF-16
byte[] utf8Text = Encoding.UTF8.GetBytes(sourceData);
byte[] utf32Text = Encoding.UTF32.GetBytes(sourceData);
// The DataFormats class does not provide data format fields for denoting
// UTF-32 and UTF-8, which are seldom used in practice; the following strings
// will be used to identify these "custom" data formats.
string utf32DataFormat = "UTF-32";
string utf8DataFormat = "UTF-8";
// Store the text in the data object, letting the data object choose
// the data format (which will be DataFormats.Text in this case).
dataObject.SetData(sourceData);
// Store the Unicode text in the data object. Text data can be automatically
// converted to Unicode (UTF-16 / UCS-2) format on extraction from the data object;
// Therefore, explicitly converting the source text to Unicode is generally unnecessary, and
// is done here as an exercise only.
dataObject.SetData(DataFormats.UnicodeText, unicodeText);
// Store the UTF-8 text in the data object...
dataObject.SetData(utf8DataFormat, utf8Text);
// Store the UTF-32 text in the data object...
dataObject.SetData(utf32DataFormat, utf32Text);
查询数据对象以获取可用格式
由于一个数据对象可包含任意数量的数据格式,数据对象包含用于检索可用数据格式列表的功能。
下面的示例代码使用 GetFormats 重载获取一个字符串数组,该数组用于表示某数据对象中可用的所有数据格式(包括本机和可自动转换的格式)。
DataObject dataObject = new DataObject("Some string data to store...");
// Get an array of strings, each string denoting a data format
// that is available in the data object. This overload of GetDataFormats
// returns all available data formats, native and auto-convertible.
string[] dataFormats = dataObject.GetFormats();
// Get the number of data formats present in the data object, including both
// auto-convertible and native data formats.
int numberOfDataFormats = dataFormats.Length;
// To enumerate the resulting array of data formats, and take some action when
// a particular data format is found, use a code structure similar to the following.
foreach (string dataFormat in dataFormats)
{
if (dataFormat == DataFormats.Text)
{
// Take some action if/when data in the Text data format is found.
break;
}
else if(dataFormat == DataFormats.StringFormat)
{
// Take some action if/when data in the string data format is found.
break;
}
}
有关查询数据对象以获取可用数据格式的更多代码示例,请参见如何:列出数据对象中的数据格式。 有关查询数据对象以了解是否存在特定数据格式的示例,请参见如何:确定数据格式是否存在于数据对象中。
从数据对象检索数据
从数据对象检索特定格式的数据只需调用 GetData 方法之一并指定所需的数据格式。 可以使用 GetDataPresent 方法之一来检查是否存在特定数据格式。 GetData 返回 Object 中的数据;根据数据格式,此对象可以强制转换为特定类型的容器。
下面的示例代码使用 GetDataPresent(String) 重载首先检查是否存在指定的数据格式(以本机方式或自动转换)。如果存在指定的格式,则该示例使用 GetData(String) 方法检索数据。
DataObject dataObject = new DataObject("Some string data to store...");
string desiredFormat = DataFormats.UnicodeText;
byte[] data = null;
// Use the GetDataPresent method to check for the presence of a desired data format.
// This particular overload of GetDataPresent looks for both native and auto-convertible
// data formats.
if (dataObject.GetDataPresent(desiredFormat))
{
// If the desired data format is present, use one of the GetData methods to retrieve the
// data from the data object.
data = dataObject.GetData(desiredFormat) as byte[];
}
有关从数据对象检索数据的更多代码示例,请参见如何:以特定数据格式检索数据。
从数据对象中移除数据
不能直接从数据对象中移除数据。 若要从数据对象中有效移除数据,请按照以下建议步骤操作:
新建一个只包含要保留的数据的数据对象。
将所需的数据从旧数据对象“复制”到新数据对象。 若要复制数据,请使用 GetData 方法之一检索包含原始数据的 Object,然后使用 SetData 方法之一将数据添加到新数据对象中。
使用新数据对象替换旧数据对象。
说明: |
---|
即使数据和数据格式与以前的调用完全一样,SetData 方法也只将数据添加到数据对象中,而并不替换数据。对同一数据和数据格式调用 SetData 两次会导致数据-数据格式在数据对象中出现两次。 |