How to: Provide Custom Toolbox Items Using the Managed Package Framework
A VSPackage based on the Managed Package Framework can extend Visual Studio Toolbox functionality by adding controls, objects derived from ToolboxItem objects. Each ToolboxItem is implemented by an object derived from Component.
Toolbox Item Provider VSPackage
A VSPackage based on the Managed Package Framework must register itself as a Toolbox control provider through .NET Framework attributes and handle Toolbox-related events.
To configure a VSPackage as a Toolbox Item Provider
Create an instance of the ProvideToolboxItemsAttribute applied to the class implementing Package. For example:
namespace Vsip.LoadToolboxMembers { [ProvideToolboxItems(14)] [DefaultRegistryRoot("Software\\Microsoft\\VisualStudio\\8.0")] [InstalledProductRegistration(false, "#100", "#102", "1.0", IconResourceID = 400)] [ProvideLoadKey("Standard", "1.0", "Package Name", "Company", 1)] [ProvideMenuResource(1000, 1)] [Guid("YYYYYYYY-YYYY-YYYY-YYYY-YYYYYYYYYYYY")] public class LoadToolboxMembers : Package {
注意
The constructor for ProvideToolboxItemsAttribute takes an integer version number as an argument. The Visual Studio environment uses this version number to determine if a VSPackage providing ToolboxItem objects must be reloaded or if cached information can be used by the Toolbox. To guarantee reloading of a VSPackage when providing a ToolboxItem that is under development, always increment this version number after any modification.
If the ToolboxItem objects provide non-standard Toolbox Clipboard formats, an instance of ProvideToolboxFormatAttribute must be applied to the class implementing the Package object for each Clipboard format supported by the ToolboxItem objects that the VSPackage provides.
For more information on supported Toolbox Clipboard formats, see Toolbox (Visual Studio SDK).
注意
If a VSPackage indicates that it provides any ToolboxItem objects with non-standard Clipboard formats, the Visual Studio environment assumes that only those formats indicated by the ProvideToolboxFormatAttribute instances applied to a VSPackage's Package class implementation are supported by the VSPackage. If a VSPackage needs to support the default Clipboard formats as well as a non-standard format, it must apply an instance of ProvideToolboxFormatAttribute for each default format as well as the non-standard format.
If the VSPackage provides the dynamic configuration of ToolboxItem, it must:
Apply an instance of ProvideToolboxItemConfigurationAttribute constructed using the Type that the package uses to implement the IConfigureToolboxItem interface.
On a public class independent of the VSPackage's Package, the VSPackage must implement the IConfigureToolboxItem interface.
An instance of the ProvideAssemblyFilterAttribute must be applied to the class implementing IConfigureToolboxItem, using a string containing a selection criteria (filter) as the argument to the ProvideToolboxItemConfigurationAttribute instance's constructor.
For information on how to notify the Visual Studio environment that a VSPackage provides Toolbox controls, see Registering Toolbox Support Features.
For an example illustrating how one might implement IConfigureToolboxItem support, see Walkthrough: Dynamic Customization of ToolboxItem Configuration.
VSPackages providing a ToolboxItem must handle ToolboxInitialized and ToolboxUpgraded events.
Implement handlers for the ToolboxInitialized and ToolboxUpgraded events:
private void OnToolboxUpgraded(object sender, EventArgs e) { OnToolboxInitialized(send,e); } private void OnToolboxInitialized(object sender, EventArgs e) { //Make sure all toolbox items are added. }
Subscribe to the ToolboxInitialized and ToolboxUpgraded events.
This is typically done in the Package implementation's Initialize method:
protected override void Initialize() { ToolboxInitialized += new EventHandler(OnToolboxInitialized); ToolboxUpgraded += new EventHandler(OnToolboxUpgraded); }
For an example of how to implement handlers for ToolboxInitialized and ToolboxUpgraded events, see Walkthrough: Autoloading Toolbox Items.
Toolbox Control Creation
The underlying implementation of a Toolbox control must be derived from Component and encapsulated in the default or a derived implementation of the ToolboxItem object.
The easiest way to provide a Component-derived implementation of Toolbox controls is by extending an object derived from Control, in particular, the UserControl class.
To create Toolbox controls
Use Solution Explorer's Add New Item command to create a Toolbox object that implements UserControl.
public partial class ToolboxControl1 : UserControl { public ToolboxControl1() { InitializeComponent(); } private void button1_Click(object sender, EventArgs e) { MessageBox.Show("Hello world from" + this.ToString()); } private void ToolboxItem1_Load(object sender, EventArgs e) { } }
For more information on authoring Windows Forms controls and toolbox controls, see Developing Custom Windows Forms Controls with the .NET Framework or Walkthrough: Autoloading Toolbox Items.
(Optional) An application can choose to use a custom object derived from the ToolboxItem object to provide its Toolbox control to the Toolbox.
注意
Any class derived from the ToolboxItem object must have an instance of the SerializableAttribute applied to it.
A custom implementation derived from ToolboxItem can extend an application by providing greater control over how the ToolboxItem data is serialized, enhanced handling of designer metadata, support for non-standard Clipboard formats, and functionality that allows end-user interaction.
In the example, users are prompted by a dialog box to select features:
[ToolboxItemAttribute(typeof(CustomControl))] [Serializable] class CustomControl : ToolboxItem { public CustomControl(Type type) : base(typeof(CustomControl)) {} public CustomControl(Type type, Bitmap icon) : base(typeof(SCustomControl)) { this.DisplayName = "CustomContorl"; this.Bitmap = icon; } private CustomControl(SerializationInfo info, StreamingContext context) { Deserialize(info, context); } protected override IComponent[] CreateComponentsCore(IDesignerHost host) { CustomControlDialog dialog = new CustomControlDialog(host); DialogResult dialogResult = dialog.ShowDialog(); if (dialogResult == DialogResult.OK) { IComponent component = (IComponent)dialog.CustomInstance; IContainer container = host.Container; container.Add(component); return new IComponent[] { component }; } else { return new IComponent[] {}; } } }
注意
It is also possible for a class derived from the ToolboxItem object to provide its own self-contained implementation of the underlying control. That class is then responsible for creating and supplying all underlying components.
Explicit Addition of Toolbox Items
To be added to the Toolbox, a control must be contained in an instance of ToolboxItem or of an object derived from ToolboxItem and then be added to the Toolbox using the IToolboxService interface.
To encapsulate and add Toolbox controls
Encapsulate the Component implementation in an instance of a ToolboxItem object or a ToolboxItem-derived object by calling that object's Initialize method with the implementing component's System.Type:
ToolboxItem customItem = new ToolboxItem() ; if (customItem != null) { customItem.Initialize(userControl); }
Above is an example of an object userControl derived from UserControl (an instance of the ToolboxControl1 object shown above) being used to construct a new ToolboxItem.
注意
The default implementation of the ToolboxItem constructor taking a System.Type argument (ToolboxItem(Type) constructor calls the ToolboxItem object's Initialize method.
Use the Toolbox service (IToolboxService) to add the ToolboxItem object constructed from the underlying control implementation.
In the example below, access to the Toolbox service is obtained, some of the properties of the ToolboxItem instance customItem are set, and then customItem is added to the Toolbox:
IToolboxService toolboxService = GetService(typeof(IToolboxService)) as IToolboxService; customItem.Bitmap = new System.Drawing.Bitmap(ToolboxControl1,"Control1.bmp:); customItem.DisplayName= "Custom Item"; toolboxService.AddToolboxItem(item, "Custom Tab");
Using Reflection to Add Toolbox Controls
Applying attributes to the class implementing a toolbox control allows the Visual Studio environment or a Visual Studio SDK based application to use reflection to automatically detect and properly add controls to the Toolbox.
To apply reflection and attributes to Toolbox controls
Identify all objects used to implement Toolbox controls with instances of ToolboxItemAttribute.
The type of instance of ToolboxItemAttribute to an object will determines if and how a ToolboxItem is constructed from it.
Applying an instance of ToolboxItemAttribute constructed with a BOOLEAN value of false to an object makes that object unavailable to the Toolbox through reflection.
This can be useful to isolate an object, such as a UserControl from the Toolbox during development.
Applying an instance of ToolboxItemAttribute constructed with a BOOLEAN value of true to an object makes that object available to the Toolbox through reflection and requires that the object be added to the Toolbox using a default ToolboxItem object.
Applying an instance of ToolboxItemAttribute constructed with the Type of a custom object derived from ToolboxItem makes the object available to the Toolbox through reflection and requires that the object be added to the Toolbox using this custom object derived from ToolboxItem.
Specify (to the Visual Studio environment's reflection mechanism) the bitmap to use for displaying the Toolbox control in the Toolbox by adding an instance of ToolboxBitmapAttribute to the Toolbox control implementation.
If needed, apply instances of ToolboxItemFilterAttribute to ToolboxItem objects to use reflection to statically mark them for use with objects that have a matching attribute.
In the example below, a Toolbox control's implementation has an instance of ProvideAssemblyFilterAttribute applied to it, which makes that control available in the Toolbox only when the current working document is a UserControl designers
[ToolboxItemFilter(System.Windows.Forms.UserControl",ToolboxItemFilterType.Require)] [SerializableAttribute()] //ToolboxItem implementations much has this attribute. [GuidAttribute("XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX")] internal class CustomToolboxItem : ToolboxItem
There are three basic techniques for using reflection to autoloading ToolboxItem.
Using the ToolService Functionality to Retrieve Toolbox Controls
The ToolboxService provides VSPackages with the static GetToolboxItems methods that use reflection to scan assemblies for all types that support toolbox items, and return items for those types. To be returned, a toolbox item must:
Be public.
Implement the IComponent class.
Not be abstract.
Have a ToolboxItemAttribute on its type.
Not have a ToolboxItemAttribute set to false on its type
Not contain generic parameters.
To obtain this list
Create an instance of Assembly referring to the assembly that is to be scanned for ToolboxItem objects.
注意
To obtain an instance of Assembly for the current assembly, use the static method GetExecutingAssembly.
Call GetToolboxItems, returning an ICollection object containing a list of the appropriate objects.
注意
If an object in the returned ICollection has a valid instance of ToolboxBitmapAttribute assigned to its implementation, the GetToolboxItems method will set the ToolboxItem object's Bitmap property.
Use GetService to obtain access to IToolboxService, and use its AddToolboxItem method to add items from the returned ICollection object to the Toolbox.
The code below queries the running application and obtains a list of all its ToolboxItem objects and loads them. For an example illustrating this in running code, see the Initialization method in Walkthrough: Dynamic Customization of ToolboxItem Configuration.
protected ICollection ToolboxItemList = null; ToolboxItemList = ToolboxService.GetToolboxItems(Assembly.GetExecutingAssembly(), ""); if (ToolboxItemList == null){ throw new ApplicationException("Unable to generate a toolbox Items listing for " + GetType().FullName); } IToolboxService toolboxService = GetService(typeof(IToolboxService)) as IToolboxService; foreach (ToolboxItem itemFromList in ToolboxItemList){ toolboxService.AddToolboxItem(itemFromList, CategoryTab); }
Using Embedded Text Resources to Autoload Toolbox Controls
A text resource in an assembly containing a properly formatted list of Toolbox controls can be used by ParseToolboxResource to automatically load a Toolbox control if properly formatted.
A text resource containing a list of objects to load must be available in an assembly accessible to the VSPackage.
To add and make available a text resource to the assembly
In Solution Explorer, right-click a the project.
Point to Add, then click New Item.
In the Add New Item dialog box, select Text File and supply a name.
In Solution Explorer, right-click the newly created text file and set the Build Action property to Embedded Resource.
Entries for the Toolbox control to be loaded must contain the name of the implementing class, the name of the assembly containing it.
For information on the format of Toolbox controls entries to the embedded text resource, see the ParseToolboxResource reference page.
Set up a search path for the files containing the assemblies hosting Toolbox control objects.
ParseToolboxResource, searches only directories specified in the registry entry HKEY_CURRENT_USER\Software\Microsoft\VisualStudio\<version>\AssemblyFolders, where <version> is the version number of the release of Visual Studio (for example, 8.0).
注意
The root path of HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\<Version> can be overridden with an alternate root when the Visual Studio shell is initialized, or use of DefaultRegistryRootAttribute. For more information see, Command-Line Switches (Visual Studio SDK).
For details on the correct format of the AssemblyFolder registry entries, see the ParseToolboxResource reference page.
Obtain an instance of Synchronized accessing the embedded text resource, and, if localization support is needed for category names, an instance of ResourceManager, and use these to invoke the ParseToolboxResource method.
ResourceManager rm = new ResourceManager("TbxCategories", Assembly.GetExecutingAssembly()); Stream toolboxStream = TbxItemProvider.GetType().Assembly.GetManifestResourceStream("ToolboxItems.txt"); if (toolboxStream != null) { using (TextReader reader = new StreamReader(toolboxStream)) { ParseToolboxResource(reader, rm); }
In the example above, a list contained in an embedded text resource in the assembly containing the class TbxItemProvider is passed to ParseToolboxResource along with the TbxCategories string resources.
The method will search all the files containing assemblies in the directories specified under the AssemblyFolders registry entry for the Toolbox controls listed in the resource and load them.
注意
If a Toolbox control found by ParseToolboxResource has a valid instance of ToolboxBitmapAttribute assigned to its implementation, ParseToolboxResource will set the bitmap used to display the Toolbox control.
Explicitly Using Reflection to Autoload Toolbox Controls
If it is necessary to explicitly query assemblies for information about the Toolbox controls they contain, rather than delegating the task to GetToolboxItems, this can be done.
To explicitly use reflection to autoload Toolbox controls
Create an instance of Assembly, referring to each assembly that is to be scanned for ToolboxItem objects.
注意
To obtain an instance of Assembly for the current assembly, use the static method GetExecutingAssembly.
For each assembly to be scanned, use the Assembly object's GetTypes method to obtain a list of each System.Type in the assembly.
Verify that the type is not abstract and supports the IComponent interface (all implementations of Toolbox controls used to instantiate a ToolboxItem object must implement this interface).
Obtain the attributes of Type and use this information to determine if the VSPackage wishes to load the object.
注意
Although in principal it is possible to create a ToolboxItem object from an IComponent interface implementation without an instance of ToolboxItemAttribute not set to false applied to it, we do not recommend doing so.
Use GetConstructor to obtain constructors for the ToolboxItem objects that the Toolbox controls require.
Construct the ToolboxItem objects and add them to the Toolbox.
To see an example illustrating explicit use of reflection to obtain and autoload Toolbox controls, see the CreateItemList described in Walkthrough: Autoloading Toolbox Items.
Additional Toolbox Control Configuration
A VSPackage can exercise additional control over when and how a Toolbox control is displayed by the Toolbox, through the implementation of IConfigureToolboxItem, and use of ProvideAssemblyFilterAttribute, and ProvideToolboxItemConfigurationAttribute.
Applying ToolboxItemFilterAttribute instances to a class provides only static control over when and how a Toolbox control is available.
To create dynamic configuration support for Toolbox controls
Construct a class implementing the IConfigureToolboxItem interface as part of a VSPackage.
注意
The IconfigureToolboxItem interface must not be implemented on the same class which provides a VSPackage's implementation of Package.
Associate the implementation of IConfigureToolboxItem with the objects in specific assemblies by applying an instance of the ProvideAssemblyFilterAttribute to it.
The example below supplies a dynamic configuration for Toolbox control object assemblies within the Vsip.* namespace and requiring that certain ToolboxItem objects be visible only with UserControl-based designers and other never visible with UserControl-based designers.
[ProvideAssemblyFilterAttribute("Vsip.*, Version=*, Culture=*, PublicKeyToken=*")] [GuidAttribute("XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX")] public sealed class ToolboxConfig : IConfigureToolboxItem { public ToolboxConfig() { } /// <summary> /// Adds extra configuration information to this toolbox item. /// </summary> public void ConfigureToolboxItem(ToolboxItem item) { if (item == null) return; //hide from .NET Compact Framework on the device designer. ToolboxItemFilterAttribute newFilter = null; if (item.TypeName == typeof(ToolboxControl1).ToString()) { newFilter = new ToolboxItemFilterAttribute("System.Windows.Forms.UserControl", ToolboxItemFilterType.Require); } else if (item.TypeName == typeof(ToolboxControl2).ToString()) { newFilter = new ToolboxItemFilterAttribute("System.Windows.Forms.UserControl", ToolboxItemFilterType.Prevent); } if (newFilter != null) { ArrayList array = new ArrayList(); array.Add(newFilter); item.Filter = (ToolboxItemFilterAttribute[]) array.ToArray(typeof(ToolboxItemFilterAttribute)); } } } }
Register a VSPackage as providing a specific implementation of IConfigureToolboxItem by applying an instance of ProvideToolboxItemConfigurationAttribute to the VSPackage's implementation of Package.
The example below would inform the Visual Studio environment that the package implemented by Vsip.ItemConfiguration.ItemConfiguration provides the class Vsip.ItemConfiguration.ToolboxConfiguration to support dynamic ToolboxItem.
[ProvideToolboxItemsAttribute(3)] [DefaultRegistryRoot("Software\\Microsoft\\VisualStudio\\8.0")] [InstalledProductRegistration(false, "#100", "#102", "1.0", IconResourceID = 400)] [ProvideLoadKey("Standard", "1.0", "Package Name", "Company", 1)] [ProvideMenuResource(1000, 1)] [ProvideToolboxItemConfigurationAttribute(typeof(ToolboxConfig))] [GuidAttribute("YYYYYYYY-YYYY-YYYY-YYYY-YYYYYYYYYYYY")] public class ItemConfiguration : Package
Custom Drag-and-Drop Support
In addition to being added to the Toolbox itself, ToolboxItem objects and their implementations can be used to extend the drag-and-drop support in the Visual Studio IDE. This can allow arbitrary Clipboard formats to be exposed to the Toolbox and in editors.
VSPackages based on the Managed Package Framework must register as providing custom Toolbox item Clipboard formats, by applying an instance of ProvideToolboxFormatAttribute to the class implementing Package.
For more information on registering as a Toolbox provider, see Registering Toolbox Support Features.
To provide custom Clipboard formats and drag-and-drop support with Toolbox controls
Create an implementation of the ToolboxItemCreatorCallback delegate.
This implementation should return a ToolboxItem object that supports the non-standard Clipboard format.
For an example implementation of a ToolboxItemCreatorCallback delegate, see the ToolboxItem and ToolboxItemCreatorCallback reference pages.
Make this implementation of the ToolboxItemCreatorCallback delegate available to the Visual StudioToolbox for a non-standard toolbox by calling AddCreator.
[GuidAttribute("7D91995B-A799-485e-BFC7-C52545DFB5DD")] [ProvideToolboxFormatAttribute("MyFormat")] public class ItemConfiguration : MSVSIP.Package { public override void Initialize() { /* */ //"Adding this class as a ToolboxItemCreator"); IToolboxService toolbox = (IToolboxService)host.GetService(typeof(IToolboxService)); if (toolbox != null) { toolboxCreator = new ToolboxItemCreatorCallback(this.OnCreateToolboxItem); toolbox.AddCreator(toolboxCreator, "MyFormat", host); } private ToolboxItem OnCreateToolboxItem(object serializedData, string format) { /* */ } } }
See Also
Concepts
Registering Toolbox Support Features
How to: Provide Custom Toolbox Items Using Interop Assemblies