Blog Home  Home Feed your aggregator (RSS 2.0)  
Introduction to Designers - Manuel Abadia's ASP.NET stuff
 
# Wednesday, March 29, 2006

Creating cool controls is only the first half of the work. The second half of the work is to add rich design time support in order to make it easy to use and improve productivity.

The following diagram provides an overview of the design-time architecture in the .NET Framework:

Design Time Architecture

There are several ways to extend the design time experience for your control:

• Designers: A control designer act as a mediator between the host environment and the run time control, customizing the control appearance and interaction with the user.
• Type Converters: A type converter allows converting one type to another type. The most common type of conversion is to convert an object to and from a string representation of the type.
• UI Type Editor: An specialized editor to modify a property using a windows form or a drop down list.
• Toolbox item: A class that act as a mediator between the component and the toolbox.

I’m going to talk about Designers for the data source controls.
There are several classes to help us when we’re implementing our own designer:

• ControlDesigner
• ContainerControlDesigner
• CompositeControlDesigner
• BaseDataBoundControlDesigner
• DataSourceDesigner
• HierarchicalDataSourceDesigner


To add support to out data source control we’re interested in the DataSourceDesigner class. To understand what DataSourceDesigner offer us, let’s take a look at the base classes and implemented interfaces:

System.ComponentModel.Design.ComponentDesigner
  System.Web.UI.Design.HtmlControlDesigner
     System.Web.UI.Design.ControlDesigner
        System.Web.UI.Design.DataSourceDesigner


System.ComponentModel.Design.ComponentDesigner: ITreeDesigner, IDesigner, IDisposable, IDesignerFilter, IComponentInitializer

IDesignerFilter: A component exposes some properties, attributes and events to the design time environment that may not be the same properties, attributes and events that the component really has. The PreFilter* methods are used to add items and the PostFilter* methods are used to change or remove items.

For example, if the Visible property is set to true in design time and there wasn’t any kind of filtering, the component will not be visible and it will be difficult to edit the component. However, if we replace the real Visible property for another property just for design time we avoid that problem

IComponentInitializer: This interface is used to initialize a component with default values, mainly used by toolbox items.

IDisposable: this interface doesn’t need presentation.

IDesigner: this interface provides the basic functionality for a designer: access to the Component and the Verbs (actions supported by the designer), custom initialization when the designed is created (Initialize) and default action when the user double clicks on the component (DoDefaultAction).

ITreeDesigner: as a component can have associated components, this interface lets a component navigate through the designers of the associated components (upwards using the Parent property or downwards using the Children property).

The System.ComponentModel.Design.ComponentDesigner class has the following properties and methods:

public class ComponentDesigner : ITreeDesigner, IDesigner, IDisposable, IDesignerFilter, IComponentInitializer

{

        #region Properties

 

        public virtual DesignerActionListCollection ActionLists { get; }

        public virtual DesignerVerbCollection Verbs { get; }

 

        public IComponent Component { get; }

        protected virtual IComponent ParentComponent { get; }

        public virtual ICollection AssociatedComponents { get; }

 

        protected bool Inherited { get; }

        protected virtual InheritanceAttribute InheritanceAttribute { get; }

 

        protected ComponentDesigner.ShadowPropertyCollection ShadowProperties { get; }

 

        #endregion

 

        #region Methods

 

        public ComponentDesigner();

 

        public virtual void Initialize(IComponent component);

        public virtual void InitializeExistingComponent(IDictionary defaultValues);

        public virtual void InitializeNewComponent(IDictionary defaultValues);

 

        public void Dispose();

        protected virtual void Dispose(bool disposing);

 

        public virtual void DoDefaultAction();

 

        protected virtual void PreFilterAttributes(IDictionary attributes);

        protected virtual void PreFilterEvents(IDictionary events);

        protected virtual void PreFilterProperties(IDictionary properties);

        protected virtual void PostFilterAttributes(IDictionary attributes);

        protected virtual void PostFilterEvents(IDictionary events);

        protected virtual void PostFilterProperties(IDictionary properties);

 

        protected void RaiseComponentChanging(MemberDescriptor member);

        protected void RaiseComponentChanged(MemberDescriptor member, object oldValue, object newValue);

 

        protected virtual object GetService(Type serviceType);

 

        protected InheritanceAttribute InvokeGetInheritanceAttribute(ComponentDesigner toInvoke);

 

        #endregion

}

 

As you can see, most methods/properties are implementations of the interfaces described above. The Inheritance related properties are used in windows forms for visual inheritance so they’re not useful for ASP.NET.

The implementation of Initialize listens for changes in component names to update the component in case the user changes the name of the component.
The implementation of DoDefaultAction is to search for the DefaultEvent and create a method that handles the event (if there wasn’t one created).

There are a lot of services available in design time to perform various tasks. To access them you’ll use the GetService method. As it’s very common to change the component, the RaiseComponentChanging and RaiseComponentChanged are shortcuts to notify the IComponentChangeService that a component is going change or has changed.

IDesignerFilter is implemented explicitly calling the virtual methods of the same name. If you override any of these methods, be sure to call the base method because some processing is done in this class (mainly related to visual inheritance and settings persistence).

As it’s very common in a designer to override properties of the component there’s a collection called ShadowProperties that can help us to store the overridden properties.

Finally, the ActionList property contains all the stuff available in the smart tag.

As rendering is done using GDI+ for WinForms and using HTML for ASP.NET, there are different base classes for each one:  System.Windows.Forms.Design.ControlDesigner and System.Web.UI.Design.ControlDesigner. We are interested only in the ASP.NET designer so the next step is to understand System.Web.UI.Design.ControlDesigner.

ControlDesigner is not a direct descendant from System.ComponentModel.Design.ComponentDesigner. Instead, it inherits from HtmlControlDesigner, that only adds the Expressions property (where you can edit the data bindings expressions for the control) in the PreFilterProperties method.

The control class has a DesignerAttribute(typeof(ControlDesigner)) so if we don’t specify another designer, ControlDesigner will be used for our controls.

In the next days I’ll explain a bit the ControlDesigner and DataSourceDesigner classes.

Wednesday, March 29, 2006 5:38:13 PM (Romance Daylight Time, UTC+02:00)  #    Comments [3]   ASP.NET  |  Tracked by:
"DataSourceControls summary" (Manuel Abadia's ASP.NET stuff) [Trackback]
http://www.manuelabadia.com/blog/PermaLink,guid,7cef4a16-10ec-44e5-8f3c-36a977b8... [Pingback]
Copyright © 2014 Manuel Abadia. All rights reserved.
DasBlog 'Portal' theme by Johnny Hughes.