Sitefinity CMS

Implementing Control Designers on Custom Control Send comments on this topic.
See Also
Developing with Sitefinity > Controls > Adding New Controls to Sitefinity > Custom Controls > Implementing Control Designers on Custom Control

Glossary Item Box

Depending on the type of control, various settings must be done for creating a designer for an ASP.Net control or a custom control. This topic provides sample code for illustration of the settings that need to be done in order to build a Control Designer in Sitefinity.   

In this topic, "ASP.Net controls" is used for both the standard ASP.Net controls and the controls provided in Sitefinity (currently not all of the Sitefinity controls have designers implemented for them).

 

Building a Designer for ASP.Net Controls

To build a designer for an ASP.Net control, there are several settings to be done. A mapping of the module to the control designer should be added to the web.config. Also, a template of that designer should be added to the project. Lastly, there are some important settings and inherited methods that should be implemented in the designer's class. The following sections cover the essential settings of each of the described parts of a designer.

 

web.config Settings

In order to create a designer of an existing ASP.Net control, a mapping must be added to the web.config. At the controlDesigners tag, add an <add> tag with key and value attributes for the control. The key attribute represents the full name of the control type, while the value one represents the namespace and the assembly of the designer. The following code illustrates the mapping for the Image control:

web.config Copy Code
<framework>
 
...
 
<controlDesigners>
   
<add key="System.Web.UI.WebControls.Image" value="Telerik.Cms.Web.UI.Design.ImageControlDesigner, Telerik.Cms.Web.UI" />
 
</controlDesigners>
</
framework>

In the above code example, "System.Web.UI.WebControls.Image" is the full name of the Image type. "Telerik.Cms.Web.UI.Design.ImageControlDesigner" is the namespace where the control designer is situated, and "Telerik.Cms.Web.UI" is its assembly.  

 

Template Settings

The ImageControlDesigner.ascx file is a template and represents a mix of HTML elements and ASP.NET controls that make up the layout for a particular control designer. Templates customize a control's user interface.

Add the template for the control in a special template folder in that control such as the following path:

 /<your_project>/Sitefinity/Admin/ControlTemplates/ControlEditors/

 

ImageControlDesigner.ascx Copy Code
<div class="ctrlProps">
 
<div class="ctrlContent">
   
<div class="ctrlContentImage">
     
<div class="ctrlContentImageColumn">
       
<p>
       
<asp:Label AssociatedControlID="ImageUrl" runat="server" Text="<$Resources>"></asp:Label>
       
<asp:TextBox ID="ImageUrl" runat="server" CssClass="txt"></asp:TextBox>
       
<asp:LinkButton ID="picker" runat="server" Text="Select" CssClass="picker"></asp:LinkButton>
       
</p>
       
<p>
       
<asp:Label AssociatedControlID="AlternateText" runat="server" Text="AlternativeText>"></asp:Label>
       
<asp:TextBox ID="AlternateText" runat="server" CssClass="txt"></asp:TextBox>
       
<em><asp:Literal ID="Literal3" runat="server" Text="AlternativeTextDescription"></asp:Literal></em>
       
</p>
     
</div>
     
<div class="ctrlContentImageColumn">
       
<p class="image-preview">
       
<asp:Image ID="imagePreview" runat="server" ImageUrl="~/Sitefinity/Admin/Themes/Default/Images/noSelectedImage.gif" />
       
</p>
       
<p>
       
<asp:Literal ID="imageName" runat="server"></asp:Literal>
       
</p>
     
</div>  
   
</div>
 
</div>
</
div>

 

The .ascx template does not inherit from ControlDesigner (an abstract class). ControlDesigner represents the base class for Sitefinity custom control designers and all custom property editors should inherit it (see the following section in this topic - Designer Class Settings). The access to the corresponding resource file and the value for the specified key are provided by Resources. For example, put in "<%$ %>" tags "Resources:SelectImage" - this will get the string value for SelectImage resource key. This should be done for all values of "Text=" - for AlternativeText, Select, etc.

 

The composite control for the given Control Designer loads the template describing its appearance as an external file with LoadTemplate method of Page class. The other possible approach for creating server control interface is to hard-code it. For example:

Hard-coded Interface Copy Code
LinkButton lnkCreateNewList = new LinkButton();
lnkCreateNewList.ID =
"newListButton";
lnkCreateNewList.Text =
"Create New List";
this.Controls.Add(lnkCreateNewList);

 

Designer Class Settings

The Designer class must inherit the abstract class ControlDesigner. The most important method in it is GetControlDesigner. It first checks for a mapping of a control to a designer in the web.config file. If such exists, the type name of that designer is taken. If not, the collection of deign-time attributes is checked looking for ControlDesignerAttribute (see the Building a Designer for Custom Controls section below). If no designer is found, then only the regular Properties tab is displayed.

ControlDesigner Copy Code
public abstract class ControlDesigner : ControlDesignerBase
{
 ...
 
public static ControlDesigner GetControlDesigner(Type type)
 {
   
if (type != null)
   {
     
string typeName = string.Empty;
     ControlDesignerCollection designerProviders = ConfigHelper.Handler.ControlDesigners;
     
if (designerProviders.ContainsKey(type.FullName))
     {
       typeName = designerProviders[type.FullName].Value;
     }
     
else
     {
       
System.ComponentModel.AttributeCollection coll = TypeDescriptor.GetAttributes(type);
       
if (coll != null)
       {
         
foreach (Attribute attr in coll)
         {
           
if (attr is ControlDesignerAttribute)
             typeName = ((ControlDesignerAttribute)attr).DesignerTypeName;
         }
       }
     }
     
if (typeName != string.Empty)
       
return (ControlDesigner)Activator.CreateInstance(
                           TypeResolutionService.ResolveType(typeName));
   }
   
return null;
 }

 

The ControlDesigner class inherits ControlDesignerBase class. The base class handles the saving and the loading of the control state. One important property is DesignedControl which gets or sets the designed control. An important method is the SetProperty one. It sets a new value for a specific property of the control. Another important method is GetEditorType. It gets the type name of the specified property. This will be useful when using a Selector in order to know what type of property is to be displayed.

ControlDesignerBase Copy Code
namespace Telerik.Framework.Web.Design
{
 
public abstract class ControlDesignerBase : CompositeControl
 {
   #region Properties
   ...
   
public Control DesignedControl
   {
     get {
return this.control; }
     set
     {
       
this.control = value;
       
if (this.control != null && this.control.Parent != null)
       {
         
this.SaveControl();
         
this.control = null;
         
this.LoadControl();
       }
       
if (base.ChildControlsCreated)
         
base.RecreateChildControls();
     }
   }
      
   #endregion
   ...
   #region Helper methods
   
/// <param name="component">The component with the property value that is to be set.</param>
   
/// <param name="properties">A collection of component properties.</param>
   
/// <param name="name">Property name.</param>
   
/// <param name="value">Property value.</param>
   
public virtual void SetProperty(object component, PropertyDescriptorCollection properties, string name, object value, out PropertyDescriptor desc)
   {
     desc = properties.Find(name, false);
     desc.SetValue(component, value);
   }
   
public virtual string GetEditorType(PropertyDescriptor desc)
   {
     
string typeName = string.Empty;
     WebEditorAttribute editorAttr = (WebEditorAttribute)desc.Attributes[
typeof(WebEditorAttribute)];
           
     
if (editorAttr != null)
       typeName = editorAttr.EditorTypeName;
     
return typeName;
   }
   ...

 

If Selector is used, the updating will/should be done in the method SelectedLists_RowCommand().

 

In the Designer class, the method base.OnPropertyChanged(EventArgs.Empty) is used for synchronization of the settings. In this way, when a the settings in the Basic tab of the module's properties are changed, the same property in the Advanced tab will be  automatically changed as well. 

base.OnPropertyChanged Copy Code
void EditorDialog_PropertyChanged(object source, PropertyValueChangedEventArgs e)
       {
           PropertyDescriptor desc;
           
this.SetProperty(component, properties, e.PropertyName, e.PropertyValue, out desc);
           
if (e.PropertyName == "ImageUrl")
               
this.SetImagePreview(e.PropertyValue.ToString());
           
base.OnPropertyChanged(EventArgs.Empty);
       }

 

 

Building a Designer for Custom Controls 

The Custom Control must declare its control designer using design-time attributes. The following code shows how the ListDisplay class declares its control designer before the class definition:

ListDisplay Attributes Copy Code
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
using System.IO;
[assembly: WebResource("Telerik.Lists.Resources.ExpandableList.js", "application/x-javascript")]
namespace Telerik.Lists.WebControls
{
   
using Telerik.Lists.Resources;
   
using Telerik.WebControls;
   
using Telerik.Cms.Web.UI;
   
using Telerik.Framework.Web.Design;
   
//[ToolboxItem(typeof(ListDisplayToolboxItem))]
   
/// <summary>
   
/// Public control that displays lists on the page
   
/// </summary>
   
[ToolboxData("<{0}:ListDisplay runat=\"server\"></{0}:ListDisplay>")]
   [DefaultProperty(
"ListsIds")]
   [ControlDesignerAttribute(
"Telerik.Lists.Design.ListsControlDesigner, Telerik.Lists")]
   
public class ListDisplay : CompositeControl, IListDisplay, IEmptyControl
   { ... }

 

This class is created for the Lists module. Using the [ControlDesignerAttribute("")] attribute, a declaration is passed of the full name of the designer as well as the assembly of the module (in this case of the Lists module).

See Also