Sitefinity ASP.NET CMS can be customized very easily using traditional ASP.NET technologies. This makes it possible for .NET developers to create new functionality by adding tools. These tools can then be used by editors (non-developers) to manage the web site.
By default, Sitefinity will automatically generate a web-based interface for custom controls/tools. For very simple controls, this interface is probably sufficient. For complex controls, this interface can quickly become overwhelming.
The interface above fails to empower editors to manage the web site; it isn't user-friendly and will intimidate non-developers. To remedy this, developers can use Control Designers to replace the default web-interface with a very user-friendly interface.
Creating a Custom Tool using an ASP.NET UserControl
Developers will primarily extend Sitefinity through ASP.NET Controls. Below is a basic UserControl that displays Text with varying emphasis based on the Priority level. (See code notes below.)
~/App_Code/CustomControlBase.cs
[Telerik.Framework.Web.Design.ControlDesigner("CustomDesigner")]
public class CustomControlBase : System.Web.UI.UserControl
{
public string Text { get; set; }
public PriorityType Priority { get; set; }
public enum PriorityType
{
Low,
Medium,
High
}
}
~/Custom/UserControls/CustomControl.ascx
<%@ Control Language="C#" AutoEventWireup="true" CodeFile="CustomControl.ascx.cs" Inherits="Custom_UserControls_CustomControl" %>
<p><asp:Label ID="Label1" runat="server" /></p>
~/Custom/UserControls/CustomControl.ascx.cs
using System;
public partial class Custom_UserControls_CustomControl : CustomControlBase
{
private const string low = "font-size: 10px;";
private const string medium = "font-size: 20px;";
private const string high = "font-size: 30px;";
protected void Page_Load(object sender, EventArgs e)
{
Label1.Text = Text;
switch (Priority)
{
case PriorityType.Low:
Label1.Style.Value = low;
break;
case PriorityType.Medium:
Label1.Style.Value = medium;
break;
case PriorityType.High:
Label1.Style.Value = high;
break;
}
}
}
Add a Sitefinity tool mapping to this UserControl in the ~/web.config file:
<configuration>
<telerik>
<cms>
<toolboxControls>
<add name="Custom Control" section="My Controls" url="~/Custom/UserControls/CustomControl.ascx" />
</toolboxControls>
</cms>
</telerik>
</configuration>
Code Notes
- The CustomControlBase class facilitates the Control Designer's access to this control's properties. (more information)
- The UserControl inherits from the CustomControlBase class instead of the UserControl class.
- The CustomControlBase class inherits from the UserControl class.
- The Control Designer is attached to this control using the ControlDesigner attribute. (more information)
- The Control Designer referenced by the ControlDesigner attribute above does not yet exist; we'll create it in the step below.

Creating a Custom Control Designer
In the step above a new UserControl and Control Base class was added to Sitefinity. In addition, a Control Designer was attached to the UserControl. In this step, we'll create the Control Designer and replace the default auto-generated interface with a user-friendly custom interface.
~/App_Code/CustomDesigner.cs
using System;
using System.Web.UI.WebControls;
public class CustomDesigner : Telerik.Framework.Web.Design.ControlDesigner
{
/// <summary>
/// Loads an external template that contains the controls & UI for the Control Designer.
/// </summary>
public override string LayoutTemplatePath
{
get { return "~/Custom/Admin/ControlDesigners/CustomDesigner.ascx"; }
}
/// <summary>
/// Executed when Control Designer is initialized.
/// </summary>
protected override void InitializeControls(System.Web.UI.Control viewContainer)
{
// Populate drop-down and preset textbox and dropdownlist if we're not in a postback.
if (!Page.IsPostBack)
{
TextBox1.Text = ((CustomControlBase) DesignedControl).Text;
DropDownList1.DataSource = Enum.GetNames(typeof (CustomControlBase.PriorityType));
DropDownList1.DataBind();
ListItem item = DropDownList1.Items.FindByText(((CustomControlBase) DesignedControl).Priority.ToString());
if (item != null)
{
DropDownList1.SelectedIndex = DropDownList1.Items.IndexOf(item);
}
}
}
/// <summary>
/// Executed automatically when the I'm done button is clicked in the Control Designer.
/// </summary>
public override void OnSaving()
{
// Set the underlying control properties to the new values.
((CustomControlBase) DesignedControl).Text = TextBox1.Text;
((CustomControlBase) DesignedControl).Priority =
(CustomControlBase.PriorityType) Enum.Parse(typeof(CustomControlBase.PriorityType), DropDownList1.SelectedValue);
}
/// <summary>
/// Gets a reference to the TextBox control contained in the LayoutTemplatePath template.
/// </summary>
protected virtual TextBox TextBox1
{
get { return base.Container.GetControl<TextBox>("TextBox1", true); }
}
/// <summary>
/// Gets a reference to the DropDownList control contained in the LayoutTemplatePath template.
/// </summary>
protected virtual DropDownList DropDownList1
{
get { return base.Container.GetControl<DropDownList>("DropDownList1", true); }
}
}
~/Custom/Admin/ControlTemplate/CustomDesigner.ascx
<%@ Control Language="C#" %>
<div class="ctrlProps">
<div class="ctrlContent">
<h3>Text to be displayed</h3>
<p class="news-location">
<asp:Label AssociatedControlID="TextBox1" Text="Enter text below:" EnableViewState="false" runat="server" />
<asp:TextBox ID="TextBox1" Columns="40" runat="server" />
</p>
<p>
<asp:Label AssociatedControlID="DropDownList1" Text="Priority:" EnableViewState="false" runat="server" />
<asp:DropDownList ID="DropDownList1" runat="server">
</asp:DropDownList>
</p>
</div>
</div>
Code Notes
- LayoutTemplatePath can be used to automatically load an external template.
- InitializeControls is executed automatically when the Control Designer is loaded. This is a great place to preset web control values based on current control settings.
- OnSaving is executed automatically when the I'm done button is clicked in the Control Designer.
- There is no code-behind for the CustomDesigner.ascx template (UserControl). You can create a code-behind file if you wish, but it's probably better to put your code-behind logic in the CustomDesigner class.
Conclusion
To get the most out of Sitefinity developers need to empower non-developers (marketing, administrators, editors, etc) to manage the web site. Control Designers allow developers to do this by creating user-friendly admin. interfaces for their tools.