Reusing and Creating Server Controls
 
Published: 08 Jan 2004
Unedited - Community Contributed
Abstract
Creating our very own server controls is very easy... but when several controls share similar behavior and functionality, it is best to reuse it through inheritance. Sometimes, it may be better to start on an entire new leaf and sometimes, turn over a new forest. This is the second article in the series that Justin Lovell will publish over the next few weeks.
by Justin Lovell
Feedback
Average Rating: 
Views (Total / Last 10 Days): 23356/ 36

Foreword

If the first article, The Basics of Server Controls, we briefly went over how the user interface in ASP.NET is operated. We also discovered that everything that is parsed in an ASP.NET page is control, or is converted/parsed as a control. However, we looked at a sample which demonstrated that we just reused the Label control. Although not much detail was discussed on the reuse of the Label control, we will discuss that in this article.

As you probably know, the minimal inheritance that you require to create a server control is for the class to inherit (directly or indirectly) from the Control class in the System.Web.UI namespace. Other controls inherit from here but the most other important (or noteworthy control) is also the WebControl class which is found in the System.Web.UI.WebControls namespace. Almost all of our everyday used control that is built-in into the .NET Framework inherits from this class/control.

However, when it comes down to creating our own server controls, we are always faced with decisions of where to start off. We sometimes see a control that we want to modify functionality or behaviour of the normal control. Sometimes, building controls from scratch is the best option but there is still the choice of whether to use the Control class or WebControl class. I will discuss some of the advantages of going each route in this article and look at how each one is achieved.

Creating Controls from Scratch

I will start off by discussing about how to create server controls from scratch. There is two classes that you can inherit from – the Control class and the WebControl class. The Control class has no features what-so-ever – it is the essential class that is relied on by the entire user interface in an ASP.NET page.

In a WebControl class, there is additional properties and methods – most of them are protected so the inheriting class can modify the behaviour. The WebControl class is mainly built for rendering HTML a lot easier. Answer the following question below to decide if you should inherit from the WebControl class:

Is the server control going to render one big HTML container to hold all rendering in?

If you answered yes to the question, then inheriting from the WebControl class will be a better option for you to pursue. In my opinion, it is a lot easier to control the WebControl class because the rendering is broken into smaller, logical blocks.

On top of that, it also adds diversity for the page developer to add some attributes during the page life cycle (without you, as the control developer, to add extra code into your control). For example, he might want to add an OnClick attribute to your server control which renders a <table> tag so that the page developer can do his own click event (server-side or client-side – let it be his choice).

To demonstrate the simplicity that the WebControl class can have over the Control class, we will build a simple Label control (without using the built-in controls). The functionality that our Label control must achieve is:

  • Must be able to output text from its Text property or from the control's inline content.

  • The output must be enclosed in the <span> tag.

  • Must have the ability to be classed for formatting from CSS.

For the demonstration to be as simple as possible (and not to overcrowd the code), we will not persist objects to view state. First, we are going to demonstrate with the Control class:

// [C#]
[ToolboxData("<{0}:CustomLabel runat=server></{0}:CustomLabel>")]
public class CustomLabel : Control {
   private string pClassName;
   private string pText = String.Empty;
   public string ClassName {
      get { return pClassName; }
      set { pClassName = value; }
   }
   public string Text {
      get { return pText; }
      set { pText = value; }
   }
   protected override void OnInit(EventArgs e) {
      if ((Controls.Count > 0) && (Controls[0] is LiteralControl))
         Text = ((LiteralControl)Controls[0]).Text;
      base.OnInit (e);
   }
   protected override void Render(HtmlTextWriter writer) {
      writer.RenderBeginTag(HtmlTextWriterTag.Span);
      if (ClassName != null)
         writer.AddAttribute(HtmlTextWriterAttribute.Class, ClassName);
      writer.Write(Text);
      writer.RenderEndTag();
   }
}
' [VB.NET]
<ToolboxData("<{0}:CustomLabel runat=server></{0}:CustomLabel>")> _
Public Class CustomLabel
Inherits Control
   Private pClassName As String
Private pText As String = [String].Empty
   Public Property ClassName() As String
Get
Return pClassName
End Get
Set (value As String)
pClassName = value
End Set
End Property
   Public Property [Text]() As String
Get
Return pText
End Get
Set (value As String)
pText = value
End Set
End Property
   Protected Overrides Sub OnInit(e As EventArgs)
If Controls.Count > 0 AndAlso TypeOf Controls(0) Is LiteralControl Then
[Text] = CType(Controls(0), LiteralControl).Text
End If
      MyBase.OnInit(e)
End Sub
    Protected Overrides Sub Render(writer As HtmlTextWriter)
writer.RenderBeginTag(HtmlTextWriterTag.Span)
       If Not (ClassName Is Nothing) Then
writer.AddAttribute(HtmlTextWriterAttribute.Class, ClassName)
End If
       writer.Write([Text])
writer.RenderEndTag()
End Sub
End Class

Now, we will look at the demonstration with our custom label inheriting from the WebControl class:

// [C#]
[ParseChildren(false)]
[PersistChildren(false)]
[ToolboxData("<{0}:CustomLabel runat=server></{0}:CustomLabel>")]
public class CustomLabel : WebControl {
private string pText = String.Empty;
   public string Text {
get { return pText; }
set { pText = value; }
}
   protected override HtmlTextWriterTag TagKey {
get { return HtmlTextWriterTag.Span; }
}
   protected override void OnInit(EventArgs e) {
if ((Controls.Count > 0) && (Controls[0] is LiteralControl))
Text = ((LiteralControl)Controls[0]).Text;
      base.OnInit (e);
}
   protected override void RenderContents(HtmlTextWriter writer) {
writer.Write(Text);
}
}
' [VB.NET]
<ParseChildren(False), PersistChildren(False)> _
<ToolboxData("<{0}:CustomLabel runat=server></{0}:CustomLabel>")> _
Public Class CustomLabel
Inherits WebControl
   Private pText As String = [String].Empty
   Public Property [Text]() As String
Get
Return pText
End Get
Set (value As String)
pText = value
End Set
End Property
   Protected Overrides ReadOnly Property TagKey() As HtmlTextWriterTag
Get
Return HtmlTextWriterTag.Span
End Get
End Property
   Protected Overrides Sub OnInit(e As EventArgs)
If Controls.Count > 0 AndAlso TypeOf Controls(0) Is LiteralControl Then
[Text] = CType(Controls(0), LiteralControl).Text
End If
      MyBase.OnInit(e)
End Sub
   Protected Overrides Sub RenderContents(writer As HtmlTextWriter)
writer.Write([Text])
End Sub
End Class

Both controls pass on the same minimal functionality; however, only one of them can walk away with an “A” to their name. That “A” will be awarded to the one that inherits from the WebControl class. For the following reason – it is able to be extended very easily by both a page developer and a control developer. Some bright control developer might want to make the tag that contains the text output to be a <div> instead of a <span> tag. Some page developer might want to add some CSS style for the label's style.

For our label control that inherits from the Control class to have that same functionality as the label control that inherits from the WebControl class, a ton of additional lines needs to be added. Another consideration when deciding which one to pursue, also think of making the lives of other control developers (including yourself) to be made easier – read further into the article to learn more about it.

Reuse of Other Controls

It is a lot easier to inherit a control and do some modifications to it. The deciding factor of whether or not to take this route, is if a control already exists for the current use. If a control does exist, and it is not sealed (also known as, not inheritable; which should be the case) then go ahead – do your tweaking... why re-invent the wheel?

On the previous page, I mentioned that a control developer my want to change the tag that encloses the text to the <div> tag. The two examples below (respectively) do the exact same thing, render a <div> as the HTML which will contain the output. This one inherits the CustomLabel control (which was done on the previous page that inherited from the WebControl class):

// [C#]
public class DivLabelControl : CustomLabel {
protected override HtmlTextWriterTag TagKey {
get { return HtmlTextWriterTag.Div; }
}
}
' [VB.NET]
Public Class DivLabelControl
Inherits CustomLabel
   Protected Overrides ReadOnly Property TagKey() As HtmlTextWriterTag
Get
Return HtmlTextWriterTag.Div
End Get
End Property
End Class

The following does the same... the only difference is that it inherits from the built-in Label control.

// [C#]
public class DivLabelControl : Label {
protected override HtmlTextWriterTag TagKey {
get { return HtmlTextWriterTag.Div; }
}
}
' [VB.NET]
Public Class DivLabelControl
Inherits Label
   Protected Overrides ReadOnly Property TagKey() As HtmlTextWriterTag
Get
Return HtmlTextWriterTag.Div
End Get
End Property
End Class

There was two objectives to show you both examples:

  • Show you that re-using controls is a ton of times easier.

  • Demonstrate with the logic in “Creating Controls from Scratch” which I stated it is a lot easier to extend the one that inherited from WebControl class.

But sometimes, re-using controls is not to extend or modify functionality/behaviour. One other common purpose that I have seen controls being re-used is to stop repetitive data-binding. An example is to have a list of customers on certain pages with a DataGrid control or DropDownList control. Fair enough with me – it could be placed in an user control but why should it be restricted to the user controls. In my experience with other developer's problems, when they re-use controls for common data binding, it is best to understand and learn the page life cycle like the back of your hand. I did discuss the page life cycle in the previous article over here. And if you followed the Guidelines and Trends for Developing Controls, solving the small issues that may occur will be relatively simple.

The tip to all the developers is this – override the OnInit method, do your data binding and then call the base's OnInit method. So your code for data binding should generally, look like this:


// [C#]
protected override void OnInit(EventArgs e) {
object dataSource; /* this variable can be anything that
the control that you are overriding can be bounded to */
   // give dataSource a value by getting the data
   DataSource = dataSource;
DataBind();
base.OnInit(e);
}
' [VB.NET]
Protected Overrides Sub OnInit(e As EventArgs)
Dim datSource As Object ' this variable can be anything that
' the control that you are overriding can be bounded to
   ' give dataSource a value by getting the data
   DataSource = datSource
DataBind()
MyBase.OnInit(e)
End Sub
An Ending Note

Hopefully, that has briefed you on when and how to make a good decision of which control class to inherit from when building your next server control. Next week, I will deal with composite controls. It is a very extensive article on the different techniques that may be used with developing server controls.

Again, if you have any feedback about the article or ideas for the series, please contact me via the feed back page (which the link is located at the top of the page). Someone gave some feed back that the articles were quite lengthy and I was not stunned to hear that at all. So I broke down the series of articles a lot further and hopefully, the length of all possible code examples does not lure you away from reading the series. I thought it was lengthy at first and it is great to hear that I was not alone.



User Comments

Title: AddAttribute/RenderBeginTag sequence   
Name: Kevmeister
Date: 2005-12-08 8:50:14 PM
Comment:
Shouldn't the AddAttribute calls be executed *before* the RenderBeginTag?
Title: Sockets   
Name: Madhusudan
Date: 2004-09-08 8:37:47 AM
Comment:
Sir,
I need to distribute a control that enacpsulates the socket class. Is it possible to inherit from the socket class and write a custom web control ?
Thanks
Title: Re: composite control   
Name: Justin Lovell
Date: 2004-08-24 1:23:42 PM
Comment:
Senthil,

I have already written an article on the basics of databinding for server controls. You can read this information from here:

http://aspalliance.com/391

And if you want to see how the templates part work out, then you can also read another article that I have written over here:

http://aspalliance.com/366
Title: composite control   
Name: Senthil
Date: 2004-08-24 9:16:32 AM
Comment:
sir
I need to create a user control i want to assign various properties to it ,all the text propeties etc are felt easy to me,but i need to bind the database to my serve control and retrive data to that as like how the boundcolumn hav dataTextField like that i want to create and bound my data to the control.im struggling to it for the past wk's can u help me regd this

Product Spotlight
Product Spotlight 





Community Advice: ASP | SQL | XML | Regular Expressions | Windows


©Copyright 1998-2024 ASPAlliance.com  |  Page Processed at 2024-03-28 7:12:25 PM  AspAlliance Recent Articles RSS Feed
About ASPAlliance | Newsgroups | Advertise | Authors | Email Lists | Feedback | Link To Us | Privacy | Search