How to: Support Toolbox Drag-and-Drop Functionality
Note
The recommended way to add custom controls to the Toolbox is to use the Toolbox Control templates that come with the Visual Studio 10 SDK, which include drag and drop support. This topic is retained only for backward compatibility, and for working with existing controls.
For more information on creating toolbox controls by using the templates, see How to: Create a Toolbox Control That Uses Windows Forms and How to: Create a Toolbox Control That Uses WPF.
VSPackages must implement drag-and-drop support if they are to use Toolbox controls on document views, such as editors or designers.
By default, all .NET Framework objects derived from System.Windows.Forms.Control automatically and transparently provide support for consuming Toolbox controls, and the procedures described below are unnecessary. The basic functionality can be extended by creating a designer.
For more information, see Windows Forms Overview and Extending Design-Time Support.
To implement basic drag-and-drop functionality
Provide drag-and-drop support by implementing IDropTarget on a view object. This provides the view with OLE drag-and-drop functionality and serialization of the control.
For more information on implementing drag-and-drop functionality, see Drag and Drop (OLE).
Drops can either be Clipboard items or controls being dropped on a designer. For information on standard Clipboard formats supported by the Visual Studio Toolbox, see Toolbox (Visual Studio SDK).
Provide a basic implementation of the IVsToolboxUser interface on a document view.
When a user attempts to drag a toolbox control to a view, the Visual Studio shell queries the view's VSPackage to see if it implements the IVsToolboxUser interface.
Implement IsSupported to return S_OK for those Toolbox formats the drop target supports. The example below checks to see if the data object is in custom Clipboard format (CF_CUSTOM_FORMAT) and whether the object is an ActiveX control.
STDMETHODIMP CustTbxUser::IsSupported(IDataObject* pDO) { HRESULT hr; STGMEDIUM stm; if (!pDO) return E_POINTER; // Determine if the data object is in the Custom clip board format // fetc is the dialog editor toolbox item template. FORMATETC fetc = { m_CF_CUSTOM_FORMAT, //Value set with RegisterClipboardFormat NULL, DVASPECT_CONTENT, // DVASCPECT_ICON might be better -1, TYMED_HGLOBAL }; if (FAILED(hr = pDO->GetData(&fetc, &stm))) { // Determine if the object is in the class-id clipboard format ... this // would be the case if the control is an activeX toolbox item. FORMATETC xfetc = { m_CF_CLSID, NULL, DVASPECT_CONTENT, // DVASCPECT_ICON might be better -1, TYMED_HGLOBAL }; if (SUCCEEDED(hr = pDO->GetData(&xfetc,&stm))) { USES_CONVERSION; GUID guid; LPSTR pData = (LPSTR)GlobalLock(stm.hGlobal); if (pData) { // Convert from the string format to a binary GUID. if (CLSIDFromString(A2W(pData), &guid) != S_OK) return E_FAIL; // HTML data objects could have CLSID format ... so any data object could // be returned as a NULL guid ... fail on null guid, obviously they are // not active X controls. if (guid == GUID_NULL) return E_FAIL; } } } return hr; }
The IDE checks for this information when a view's window first loads, and for every activation of a view's window following a reset of the Toolbox by a user through the IDE's CustomizeToolbox dialog box. Typically, the Toolbox does not display unsupported Toolbox items.
Users can set an option to display all Toolbox pages at all times. In this case, the environment does not query the editor for IsSupported.
After an IDropTarget implementation (such as the one described above) successfully handles a dropped component, the view object must notify the Visual Studio environment of this by calling DataUsed
If desired, a VSPackage can extend its drag-and-drop support by extending its IVsToolboxUser implementation.
An IVsToolboxUser implementation can support the dragging of Toolbox items to a window by selection rather than mouse action. That is, dragging an item when a user either double-clicks on a Toolbox item or single-clicks and then presses ENTER. To do this:
Implement the ItemPicked method.
This method, called by the IDE is selected through a click, or by pressing ENTER.
The method should insert the Toolbox item into the target window.
If you do not wish to support implementation by selection, the method should return S_FALSE.
In the example below, the implementation of the ItemPicked method checks if the object selected is supported, and if so deserializes it into the code:
STDMETHODIMP CustTbxUser::ItemPicked(IDataObject* pDataObject) { if (!pDataObject) return E_POINTER; UINT nIDTool; if (IsSupported(pDataObject) == S_OK) { SetToolCursor(); m_pDataObject = pDataObject; nIDTool = DeserializeObject(); // Get the focus back m_pResObject->m_spWndFrame->Show(); return S_OK; } }
Carry out the following steps to ensure that proper focus is maintained for your application:
If your editor window implements two different panes, not two different views, then call the UpdateToolboxUI method when you switch pane activations within your editor window. Only you know when activation changes occur within your window.
To properly activate the window and to ensure that command routing is updated properly, you must call the Show method on the component. This action must be taken when you are setting focus to a component window, such as an editor, created or modified by a drag-and-drop operation involving the toolbox.
A VSPackage may need to intervene in a drag operation and modify the dropped item through the IVsToolboxActiveUserHook interface.
For instance, rather than adding a new Toolbox control explicitly to the Toolbox, a VSPackage might intercept a standard Toolbox as it is dropped and replace it with a custom implementation.
To dynamically modify toolbox controls
Implement the IVsToolboxActiveUserHook method.
Whenever a Toolbox item is selected or dropped, the Toolbox queries the drop target to see if it supports the IVsToolboxActiveUserHook interface, and if it does calls the InterceptDataObject method.
The InterceptDataObject method must return a new IDataObject object to be used rather than the original IDataObject.
If the drop target does not need to override the data object, it should return its input.
A VSPackage can allow users to cycle through the contents of the Clipboard by pressing CTRL+SHIFT+V.
To support a Clipboard ring
Implement a handler for the CMDIDPasteNextTBXCBItem command using:
IOleCommandTarget for interop-assembly-based VSPackages.
OleMenuCommandService for Managed Package Frameworkâbased VSPackages. IVsToolboxClipboardCycler interface.
In the command handler, implement the AreDataObjectsAvailable method to determine whether there are any Clipboard objects to cycle through.
If there are no items on the Toolbox Clipboard, then the environment checks the system Clipboard to see if there are any items on it.
If there are items on the system Clipboard, but not on the Toolbox Clipboard, then the Clipboard ring is populated with system items.
To select the next item in the list, the implementation calls the GetAndSelectNextDataObject method.
To return to the beginning of the Clipboard cycle, call the BeginCycle method.
See Also
Tasks
Advanced Toolbox Control Development
Concepts
How to: Provide Custom Toolbox Items By Using Interop Assemblies
Registering Toolbox Support Features