Drag and Drop Overview
This topic provides an overview of drag and drop support in Windows Presentation Foundation (WPF) applications. Drag-and-drop commonly refers to a method of user interface (UI) interaction that involves using a mouse (or some other pointing device) to select one or more objects, dragging these objects over some desired drop target in the UI, and dropping them.
This topic contains the following sections.
- Drag and Drop Support in WPF
- Data and Data Objects
- Drag-and-Drop Events
- Working with Data Objects
- Related Topics
Drag and Drop Support in WPF
Drag-and-drop operations typically involve two parties: a drag source from which the dragged object originates and a drop target which receives the dropped object. The drag source and drop target may be the same application or a different application.
The type and number of objects that can be manipulated with drag-and-drop is completely arbitrary; one or more files or folders, and selections of content are some of the more common objects manipulated through drag-and-drop operations. The particular action(s) performed during a drag-and-drop operation are application specific, and often determined by context. For example, dragging a selection of files from one folder to another on the same storage device moves the files by default, whereas dragging files from a Universal Naming Convention (UNC) share to a local folder copies the files by default. The drag-and-drop facilities provided by the WPF are designed to be highly flexible and customizable to support a wide variety of drag-and-drop scenarios. Drag-and-drop supports manipulating objects within a single application, or between different applications; dragging-and-dropping between WPF applications and other Windows applications is also fully supported. Drag-and-drop falls under the more general area of data transfer; in addition to drag-and-drop, data transfer also includes using the system clipboard for copy and paste operations.
Security Note: OLE drag-and-drop does not work while in the internet zone.
Data and Data Objects
Data that is transferred as part of a drag-and-drop operation is stored in a data object. Conceptually, a data object consists of one or more pairs of:
an Object that contains the actual data, and
a corresponding data format identifier.
The data itself can consist of anything that can be represented as a base Object. The corresponding data format is a string or Type that provides a hint about what format the data is in. Data objects support hosting multiple data-(data format) pairs; this enables a single data object to provide data in multiple formats.
All data objects must implement the IDataObject interface, which provides the following standard set of methods that enable and facilitate data transfer.
Method |
Summary |
---|---|
Retrieves a data object in a specified data format. |
|
Checks to see whether the data is available in, or can be converted to, a specified format. |
|
Returns a list of formats that the data in this data object is stored in, or can be converted to. |
|
Stores the specified data in this data object. |
WPF provides a basic implementation of IDataObject in the DataObject class; the stock DataObject class is sufficient for many common data transfer scenarios.
For information on pre-defined data formats provided with WPF, see the DataFormats class reference topic.
Data objects commonly include a facility for automatically converting data stored in one format to a different format while extracting data; this facility is referred to as auto-convert.
When querying for the data formats available in a data object, auto-convertible data formats can be filtered from native data formats by calling the GetFormats(Boolean) or GetDataPresent(String, Boolean) method and specifying the autoConvert parameter as false. When adding data to a data object with the SetData(String, Object, Boolean) method, auto-conversion of data can be prohibited by setting the autoConvert parameter to false.
Drag-and-Drop Events
Drag-and-drop operations support an event driven model. Both the drag source and the drop target use a standard set of events to handle drag-and-drop operations. The following tables summarize the standard drag-and-drop events.
Drag Source Events
Event |
Summary |
---|---|
This event occurs when a drag-and-drop operation is started, and enables the drop target to send feedback information to the drag source; this feedback is commonly used by the drag source to dynamically adjust the appearance of the mouse pointer to provide feedback to the user. This is a bubbling event. |
|
This event occurs when there is a change in the keyboard or mouse button states during a drag-and-drop operation, and enables the drop source to cancel the drag-and-drop operation depending on the key/button states. This is a bubbling event. |
|
Tunneling version of GiveFeedback. |
|
Tunneling version of QueryContinueDrag. |
Drop Target Events
Event |
Summary |
---|---|
This event occurs when an object is dragged into the drop target's boundary. This is a bubbling event. |
|
This event occurs when an object is dragged out of the drop target's boundary. This is a bubbling event. |
|
This event occurs when an object is dragged (moves) within the drop target's boundary. This is a bubbling event. |
|
This event occurs when an object is dropped on the drop target. This is a bubbling event. |
|
Tunneling version of DragEnter. |
|
Tunneling version of DragLeave. |
|
Tunneling version of DragOver. |
|
Tunneling version of Drop. |
Working with Data Objects
This section describes common techniques for creating and working with data objects.
Using the DataObject Constructors
The DataObject class provides several overloaded constructors that facilitate populating a new DataObject instance with a single data-(data format) pair.
The following example code creates a new data object and uses one of the overloaded constructors (DataObject(String, Object)) to initialize the data object with a string and a specified data format. In this case the data format is specified by a string; the DataFormats class provides a set of pre-defined type strings. Auto-converting of the stored data is allowed by default.
Dim stringData As String = "Some string data to store..."
Dim dataFormat As String = DataFormats.UnicodeText
Dim dataObject As New DataObject(dataFormat, stringData)
string stringData = "Some string data to store...";
string dataFormat = DataFormats.UnicodeText;
DataObject dataObject = new DataObject(dataFormat, stringData);
For more examples of code that creates a data object, see How to: Create a Data Object.
Storing Data in Multiple Formats
A single data object is able to store data in multiple formats. Strategic use of multiple data formats within a single data object potentially makes the data object consumable by a wider variety of drop targets than if only a single data format could be represented. Note that, in general, a drag source must be agnostic about the data formats that are consumable by potential drop targets.
The following example shows how to use the SetData(String, Object) method to add data to a data object in multiple formats.
Dim dataObject As New DataObject()
Dim sourceData As String = "Some string data to store..."
' Encode the source string into Unicode byte arrays.
Dim unicodeText() As Byte = Encoding.Unicode.GetBytes(sourceData) ' UTF-16
Dim utf8Text() As Byte = Encoding.UTF8.GetBytes(sourceData)
Dim utf32Text() As Byte = 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.
Dim utf32DataFormat As String = "UTF-32"
Dim utf8DataFormat As String = "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)
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);
Querying a Data Object for Available Formats
Because a single data object can contain an arbitrary number of data formats, data objects include facilities for retrieving a list of available data formats.
The following example code uses the GetFormats overload to get an array of strings denoting all data formats available in a data object (both native and auto-convertible).
Dim dataObject As 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.
Dim dataFormats() As String = dataObject.GetFormats()
' Get the number of data formats present in the data object, including both
' auto-convertible and native data formats.
Dim numberOfDataFormats As Integer = 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.
For Each dataFormat As String In dataFormats
If dataFormat = System.Windows.DataFormats.Text Then
' Take some action if/when data in the Text data format is found.
Exit For
ElseIf dataFormat = System.Windows.DataFormats.StringFormat Then
' Take some action if/when data in the string data format is found.
Exit For
End If
Next dataFormat
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;
}
}
For more examples of code that queries a data object for available data formats, see How to: List the Data Formats in a Data Object. For examples of querying a data object for the presence of a particular data format, see How to: Determine if a Data Format is Present in a Data Object.
Retrieving Data from a Data Object
Retrieving data from a data object in a particular format simply involves calling one of the GetData methods and specifying the desired data format. One of the GetDataPresent methods can be used to check for the presence of a particular data format. GetData returns the data in a Object; depending on the data format, this object can be cast to a type-specific container.
The following example code uses the GetDataPresent(String) overload to first check if a specified data format is available (natively or by auto-convert). If the specified format is available, the example retrieves the data by using the GetData(String) method.
Dim dataObject As New DataObject("Some string data to store...")
Dim desiredFormat As String = DataFormats.UnicodeText
Dim data() As Byte = Nothing
' 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) Then
' If the desired data format is present, use one of the GetData methods to retrieve the
' data from the data object.
data = TryCast(dataObject.GetData(desiredFormat), Byte())
End If
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[];
}
For more examples of code that retrieves data from a data object, see How to: Retrieve Data in a Particular Data Format.
Removing Data From a Data Object
Data cannot be directly removed from a data object. To effectively remove data from a data object, follow these suggested steps:
Create a new data object that will contain only the data you want to retain.
"Copy" the desired data from the old data object to the new data object. To copy the data, use one of the GetData methods to retrieve an Object that contains the raw data, and then use one of the SetData methods to add the data to the new data object.
Replace the old data object with the new one.
Note |
---|
The SetData methods only add data to a data object; they do not replace data, even if the data and data format are exactly the same as a previous call. Calling SetData twice for the same data & data format will result in the data-data format being present twice in the data object. |