Reminder: All posts in this series can be found here.
The Toolbox and the DesignSurface work together to allow a developer to add new components and controls to the design surface. There are two interfaces that implement this functionality: IToolboxService and IToolboxUser.
IToolboxService defines an interface that provides methods and properties to manage and query the Toolbox capabilities in a development environment. All forms designer systems must implement the IToolboxService in their Toolbox in order to provide the expected Windows Forms UI functionality. This service is added to the ServiceContainer and can be accessed at any time. There are 15 methods and two properties in the interface which I will not cover here in detail. Many of those methods deal with adding, deleting and selecting Toolbox items.
IToolboxUser defines an interface for setting the currently selected toolbox item and indicating whether a designer supports a particular toolbox item. A forms designer will implement an IToolboxUser interface that consists of only two methods: GetToolSupported and ToolPicked. You use GetToolSupported to filter the items that can be added onto the designer.
Implementation: There are several steps you have to take to build a Toolbox for a Forms Designer system.
- Create a user interface that displays the tools to the user. This is typically implemented as a classic TreeView, or as sliding tree control that behaves much like Windows Explorer, but without grid or connection lines. Building the desired functionality can take quite a bit of time. There is a nice Code Project article that has a mostly-complete solution with multi-level tabs. There are several design decisions you will have to make before you start coding. Besides the visual representation already noted, you must decide how you will discover, categorize, and load the tools. One of the MSDN Magazine articles describes three methods: hard coding (not recommended), configuration file, and attribute decorated classes loaded from a known location and checked using reflection.
- Implement the IToolboxService. The three main members of this interface are GetSelectedToolboxItem, SerializeToolboxItem, and DeserializeToolboxItem. Other useful members include GetCursor, IsSupported, IsToolboxItem, and SelectedToolboxItemUsed.
- Plug the IToolboxService implementation into the design-time environment.
- Create a keyboard interface.
- Handle Toolbox events, such as tool selection, keyboard, mouse clicks and drag and drop.
Usage: There are four ways a developer can add a component or control to a forms designer DesignSurface; one uses the keyboard, while the other three use the mouse. The Visual Studio Toolbox functions are described here. I will talk about the changes required to the sample application to implement the Visual Studio functionality in Part 2 of this post.
- Keyboard: The Visual Studio Toolbox keyboard interface is described here. Essentially, you Ctrl+Tab/cursor to the Toolbox (or press Ctrl+Alt+X), cursor to the desired control and hit Enter. The control will be added to the DesignSurface. Ctrl+Up Arrow, Ctrl+Down Arrow, Left Arrow, and Right Arrow also have control functions within the Toolbox.
- Mouse: Double-Click a Toolbox icon. The control will be added to the DesignSurface. This has the same effect as using the keyboard method.
- Mouse: Single Click a Toolbox icon. Move the cursor over the DesignSurface, were it will turn to a Crosshair ready for you to click and drag the desired control location and size. Visual Studio customizes the Crosshair cursor with color overlay of the selected tool icon until the mouse has been clicked and released. This operation can be canceled with the Esc key.
- Mouse: Drag and Drop a Toolbox icon. Click a control icon, drag it onto the DesignSurface, and drop it where you want it. This operation can be canceled with the Esc key.
To allow the icons from the Toolbox to be added to the DesignSurface using the mouse or keyboard, the Toolbox in the sample code hooks onto the KeyDown and MouseDown events. IToolboxUser.ToolPicked is called for the Enter key or a mouse double-click. The sample code shows how to serialize the ToolboxItem into a DataObject and to DoDragDrop for when a mouse single-click event occurs. IToolboxService.SerializeToolboxItem will be called on mouse up and the item will be added to the designer.
When a new control or component is added to the DesignSurface from the Toolbox, the NameCreationService is used to give it a unique name. My discussion of this service and my modifications to the sample code are described here.