Enabling Multi-Targeting for Control Designers

This is the fourth in my blog series on Visual Studio 2010 Designer Multi-Targeting

As mentioned in my previous post, the property grid filtering is implemented through the use of a TypeDescriptionProvider which reflects against the project’s target framework.  This multi-targeting provider is attached automatically (via TypeDescriptor.AddProvider) for Windows and Web Forms controls that are created on or added to the design surface.  The following are where these automatic hook-ups take place:

WebForms:

ControlBuilder.BuildObject – covers controls created when switching from source to design view and controls added from the toolbox.

AddControlToDocument – covers controls manually created and added to the design surface.

WinForms:

DesignSurface.CreateInstance – covers controls created when the designer is opened (controls deserialized from the source code), and controls added from the toolbox.

[Component.]Container.Add (where component is directly on the design surface) – covers controls manually created and added to the design surface through a parent component.

Control vendors should be aware that these hook-ups do not cover any child controls created manually by the root control itself, unless they are explicitly added to the design surface.  However, these only need to be multi-targeting aware if any designer UI is affected by the metadata (properties, attributes, etc) from these child controls.

If necessary, you can manually hook-up a multi-targeting provider to a child control or other object by using the TypeDescriptionProviderService to create the provider:

 var mtService = (TypeDescriptionProviderService)serviceProvider.GetService(typeof(TypeDescriptionProviderService));
if (mtService != null) {
    var mtProvider = mtService.GetProvider(_childControl);
    TypeDescriptor.AddProvider(mtProvider, _childControl);
}

Note that TypeDescriptor does not publicly expose any providers in its providers list -- TypeDescriptor.GetProvider returns a node that wraps the actual provider.  If you need to check whether a multi-targeting provider has already been attached to a control or object instance, then you will need to rely on behavior from the multi-targeting provider.  It just so happens that the multi-targeting provider is injecting a ProjectTargetFrameworkAttribute onto its reflection types, which can be used to detect the provider’s existence:

 var type = TypeDescriptor.GetProvider(_childControl).GetReflectionType(typeof(object));
if (!type.IsDefined(typeof(ProjectTargetFrameworkAttribute), false)) {
    // multi-targeting provider is NOT attached
}