Metadata Filtering

Metadata filtering allows a designer to modify the set of properties, attributes and events exposed by a component or control at design time.

For example, Control has a property named Visible that determines whether the control is visible. At design time, however, the control should always remain visible, regardless of the value of this property, so that a developer can position it on the design surface. The designer for Control replaces the Visible property with its own version at design time and later restores the run-time value of this property.

To perform metadata filtering, a designer can either implement the IDesignerFilter interface, or add an ITypeDescriptorFilterService implementation to the design-time services provider that can perform metadata filtering on any component in the design-time environment.

When a component is selected at design time, the property browser queries the component for its attributes, events, and properties through the methods of a TypeDescriptor. When a component is queried for its attributes, events, and properties in design mode, any designer for the component that implements the IDesignerFilter interface is given an opportunity to modify the set of attributes, events, and properties returned by the component. The methods of any active ITypeDescriptorFilterService are called next to allow the service to do any filtering of attributes, events and properties.

A component in design mode is typically queried for its attributes, events and properties when the Refresh method of TypeDescriptor is called on the component, when the Properties window is refreshed, when design mode is established or reestablished, and when the primary selection is set. Methods of other objects or a design-time environment may call the methods of a TypeDescriptor at other times.

IDesignerFilter Interface for Component Metadata Filtering

The IDesignerFilter interface defines a set of methods that can be overridden and implemented in a designer to alter the properties, events, or attributes exposed by the component managed by the designer at design time.

Each method of the IDesignerFilter interface is prefixed with either "Pre" or "Post". Each method is suffixed with either "Attributes", "Events", or "Properties", depending on which type of member it allows you to add, change, or remove. To add any attributes, events, or properties, use the relevant method whose name begins with "Pre". To change or remove any attributes, events, or properties, use the relevant method whose name begins with "Post". The methods whose names begin with "Pre" are called immediately before the methods whose names begin with "Post".

If you want to add an attribute or attributes, implement an override of the PreFilterAttributes method that adds the new System.Attribute to the IDictionary passed to the method. The keys in the dictionary are the type IDs of the attributes. To change or remove an attribute or attributes, implement an override of the PostFilterAttributes method.

If you want to add an event or events, implement an override of the PreFilterEvents method that adds the new EventDescriptor to the IDictionary passed to the method. The keys in the dictionary are the names of the events. To change or remove an event or events, implement an override of the PostFilterEvents method.

If you want to add a property or properties, implement an override of the PreFilterProperties method that adds the new PropertyDescriptor to the IDictionary passed to the method. The keys in the dictionary are the names of the properties. To change or remove a property or properties, implement an override of the PostFilterProperties method.

Note

When a class extends a designer that implements IDesignerFilter, each PostMethodName method should call the corresponding PostMethodName method of the base class after changing its own attributes, and each PreMethodName method should call the corresponding PreMethodName method of the base class before changing its own attributes.

The following code example block shows the method signatures of the IDesignerFilter interface.

Public Interface IDesignerFilter
   Sub PostFilterAttributes(attributes As IDictionary)
   Sub PostFilterEvents(events As IDictionary)
   Sub PostFilterProperties(properties As IDictionary)
   Sub PreFilterAttributes(attributes As IDictionary)
   Sub PreFilterEvents(events As IDictionary)
   Sub PreFilterProperties(properties As IDictionary)
End Interface
public interface IDesignerFilter {
    void PostFilterAttributes(IDictionary attributes);
    void PostFilterEvents(IDictionary events);
    void PostFilterProperties(IDictionary properties);
    void PreFilterAttributes(IDictionary attributes);
    void PreFilterEvents(IDictionary events);
    void PreFilterProperties(IDictionary properties);
}

The following code example demonstrates an implementation of IDesignerFilter that adds a Color property of the designer to the associated component. You need to add a reference to System.Design.dll.

Imports System
Imports System.ComponentModel
Imports System.ComponentModel.Design
Imports System.Drawing
Imports System.Windows.Forms
Imports System.Windows.Forms.Design

Namespace IDesignerFilterSample
 _
    Public Class DesignerFilterDesigner
        Inherits ComponentDesigner        

        ' Designer color property to add to component.
        Public Property TestColor() As Color
            Get
                Return Me.intcolor
            End Get
            Set(ByVal Value As Color)
                Me.intcolor = Value
            End Set
        End Property

        ' Color for TestColor property.
        Private intcolor As Color = Color.Azure

        Public Function DesignerFilterDesigner()
        End Function 'DesignerFilterDesigner

        ' Adds a color property of this designer to the component.
        Protected Overrides Sub PreFilterProperties(ByVal properties As System.Collections.IDictionary)
            MyBase.PreFilterProperties(properties)
            ' Adds a test property to the component.
            properties.Add("TestColor", TypeDescriptor.CreateProperty(GetType(DesignerFilterDesigner), "TestColor", GetType(System.Drawing.Color), Nothing))
        End Sub 'PreFilterProperties

    End Class 'DesignerFilterDesigner

    ' Component with which the DesignerFilterDesigner is associated.
    <Designer(GetType(DesignerFilterDesigner))>  _    
    Public Class TestComponent
        Inherits Component

        Public Function TestComponent()
        End Function 'TestComponent
    End Class 'TestComponent

End Namespace
using System;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Drawing;
using System.Windows.Forms;
using System.Windows.Forms.Design;

namespace IDesignerFilterSample
{
   public class DesignerFilterDesigner : ComponentDesigner, IDesignerFilter
   {
      // Designer color property to add to component.
      public Color TestColor
      {
         get
         { return this.intcolor;   }
         set
         { this.intcolor = value; }
      }

      // Color for TestColor property.
      private Color intcolor = Color.Azure;

      public DesignerFilterDesigner()
      {}

      // Adds a color property of this designer to the component.
      protected override void PreFilterProperties(System.Collections.IDictionary properties)
      {
         base.PreFilterProperties(properties);
         // Adds a test property to the component.
         properties.Add("TestColor", TypeDescriptor.CreateProperty(typeof(DesignerFilterDesigner), "TestColor", typeof(System.Drawing.Color), null));
      }
   }

   // Component with which the DesignerFilterDesigner is associated.
   [Designer(typeof(DesignerFilterDesigner))]
   public class TestComponent : Component
   {
      public TestComponent()
      {}
   }
}

For an example of a Windows Forms control designer that implements property filtering using the IDesignerFilter interface, see the Windows Forms Designer Sample.

ITypeDescriptorFilterService for Global Design Mode Metadata Filtering

You can provide metadata filtering for any component in a design-time project by adding an ITypeDescriptorFilterService implementation to the service provider that provides services at design time, using the AddService method of the IServiceContainer interface implemented by the ISite returned by the Site property of a Component sited in design mode.

The following code example demonstrates how to add an ITypeDescriptorFilterService service called ExampleFilterService.

IDesignerHost dh = (IDesignerHost)this.Component.GetService(typeof(IDesignerHost));
if( dh != null )
{
   // First gets any previous ITypeDescriptorFilterService to replace when 
   // the current service is removed, and to call if the new service 
   // implements service chaining.
   ITypeDescriptorFilterService itdfs = 
   (ITypeDescriptorFilterService)dh.GetService(    typeof(ITypeDescriptorFilterService));
   
   oldService = (ITypeDescriptorFilterService)dh.GetService(
   typeof(ITypeDescriptorFilterService));
         
   if(oldService != null)
      // Removes any old ITypeDescriptorFilterService.
      dh.RemoveService(typeof(ITypeDescriptorFilterService));
         
   // Adds an ExampleFilterService that implements service chaining.
   dh.AddService(typeof(ITypeDescriptorFilterService), 
   new ExampleFilterService(oldService));
}

For an example ITypeDescriptorFilterService implementation, see the reference documentation for the ITypeDescriptorFilterService class.

See Also

Tasks

How to: Adjust the Attributes, Events, and Properties of a Component in Design Mode

Concepts

Base Designer Classes

Designer Verbs

How to: Implement a Designer for a Control

Type Descriptor Overview

Other Resources

Custom Designers