HomeASP.NET ASP.NET Custom Server Controls: Round Corn...
ASP.NET Custom Server Controls: Round Cornered box control in ASP.NET
This article introduces you to creating your own round cornered box control in ASP.NET. While this can be done with a flexible Table control in ASP.NET, it makes more sense to use a custom control if you plan to place many boxes in your application.
A file related to this article is available for download here.
The sample downloadable solution (zip) was entirely developed using Visual Studio.NET 2003 Enterprise Architect on Windows Server 2003 Standard Edition. But, I am confident that it would work with other versions of Windows (which support .NET 1.1) as well.
Introduction
Everyone knows that ASP.NET already contains a flexible Table control to design round cornered boxes with ease. But, if we want to place too many boxes in our application, it would be bit difficult to achieve without a custom control. Now, we shall design and develop our own custom control for repetitive use of those web boxes (containing simple messages) throughout our application.
In my previous articles, I already introduced you to how to design and implement our own Custom Server Control from the scratch. If you are quite new to the concept of Custom Controls in ASP.NET, I suggest you go through my previous articles before going through this article.
Even though I could use System.Web.UI.Control as the base class for my button control, I selected System.Web.UI.WebControls.WebControl as the base class, because of the convenience and ease. Apart from all of these, we will also look into “<EditorAttribute>” available in ASP.NET.
System.Web.UI.Control class has only a few rendering methods which could be overridden. This gives us less flexibility in developing the custom control, when we compare with the rendering methods available in the System.Web.UI.WebControls.WebControl class. Of course, some of the most important properties (such as width, height, font and so on) of the WebControl class get inherited to our control.
In this scenario, I expose nine properties, to fix border (rounded) images for our control. Before talking too much about the control, let us go through the implementation first. We will create a Visual Studio.NET 2003 solution throughout this article with more than one project.
As you know, every side of the box needs to be provided with some image (including the corners, of course). The following are the properties which handle all of those images (paths of those images).
Property ImageTopLeftURL() As String Property ImageTopMiddleURL() As String Property ImageTopRightURL() As String Property ImageMiddleLeftURL() As String Property ImageMiddleMiddleURL() As String Property ImageMiddleRightURL() As String Property ImageBottomLeftURL() As String Property ImageBottomMiddleURL() As String Property ImageBottomRightURL() As String
I hope all of the above are simple to read and understandable. I declared each of those properties with an attribute at the top as follows:
The above is the most exciting statement used with all the previous properties. The “EditorAttribute” is mainly helpful for the Visual Studio.NET designer to facilitate an editor for the value being provided to that property (similar to the “Font” property).
In this case, we attach a dialog box (Visual Studio.NET supported open dialog) to the property, to facilitate the developer in selecting a respective image from folders within the web application hierarchy. If we don’t specify the above attribute, the developer needs to remember and type the entire path of the image within the property window of Visual Studio.NET designer, as opposed to simply selecting the image file.
Starting with <TABLE>
The default “Render” method (when not overridden by us) usually calls “RenderBeginTag” before calling any other methods. Let us examine the “RenderBeginTag” method in my control step by step:
Within the above method, I am trying to call the “MyBase.AddAttributesToRender(Writer)” statement to add any design-time attributes to my control. This is a must when we use the control with the Visual Studio.NET designer. You can also override with any other attributes you want (as shown in my previous articles of the same series). From all the above statements, the conclusion would be something like: I am trying to render a “<TABLE>” tag with some attributes. Please note that the tags have not yet been closed!
Starting simply with “<TABLE>” is not enough. We need to frame 3x3 set of cells within the table. I call the first row of cells the header, second row of cells the body (or content) and third row the footer for better understanding.
In our next section, we shall see how to implement the header.
The header part mainly contains three cells (top left, top middle, top right). We need to create a new row with three cells and fill these cells with their respective images. The following is the next code fragment (a continuation from the above code fragment within the same “RenderBeginTag” method).
writer.RenderBeginTag(HtmlTextWriterTag.Tr) 'top left writer.AddAttribute(HtmlTextWriterAttribute.Width, "0px") writer.AddAttribute(HtmlTextWriterAttribute.Height, "0px") writer.RenderBeginTag(HtmlTextWriterTag.Td) If Me.ImageTopLeftURL.Trim.Length > 0 Then writer.AddAttribute(HtmlTextWriterAttribute.Src,Me.ImageTopLeftURL.Trim) writer.AddAttribute(HtmlTextWriterAttribute.Border, "0px") writer.RenderBeginTag(HtmlTextWriterTag.Img) writer.RenderEndTag() End If writer.RenderEndTag() 'td
The above code fragment starts a single row (first row in the table) and creates the first cell (top left cell). Once the image specification (path of the image) for the cell is provided, I embed it into the cell using the “<img>” tag. By default, I fixed the width to “0px,” allowing it to fit automatically based on the image size.
'top middle writer.AddAttribute(HtmlTextWriterAttribute.Width, "100%") writer.AddAttribute(HtmlTextWriterAttribute.Height, "0px") If Me.ImageTopMiddleURL.Trim.Length > 0 Then writer.AddStyleAttribute(HtmlTextWriterStyle.BackgroundImage, "url(" &Me.ImageTopMiddleURL.Trim & ")") writer.AddStyleAttribute("background-repeat", "repeat-x") End If writer.RenderBeginTag(HtmlTextWriterTag.Td) writer.RenderEndTag() 'td
As the middle cell may expand according to the content, I set the image (for the top middle cell) as a background image. I also added a style attribute which makes it repeat when expanded. And finally, the following code fragment is for the last cell (top right).
'top right writer.AddAttribute(HtmlTextWriterAttribute.Width, "0px") writer.AddAttribute(HtmlTextWriterAttribute.Height, "0px") writer.RenderBeginTag(HtmlTextWriterTag.Td) If Me.ImageTopRightURL.Trim.Length > 0 Then writer.AddAttribute(HtmlTextWriterAttribute.Src,Me.ImageTopRightURL.Trim) writer.AddAttribute(HtmlTextWriterAttribute.Border, "0px") writer.RenderBeginTag(HtmlTextWriterTag.Img) writer.RenderEndTag() End If writer.RenderEndTag() 'td writer.RenderEndTag() 'tr
The above is very similar to the first cell (top left) and I don’t think that I need to explain it much. But the important issue is that I closed the header row with the last statement.
Creating the body would also be very similar to the header. But, we need to play a trick to allow the developer to write his own message during the rendering the control. This is the only complex issue to handle in our control.
Let us first add the first cell of the row (Middle left) using the following code fragment (a continuation from the above code fragment within the same “RenderBeginTag” method).
writer.RenderBeginTag(HtmlTextWriterTag.Tr) 'middle left writer.AddAttribute(HtmlTextWriterAttribute.Width, "0px") writer.AddAttribute(HtmlTextWriterAttribute.Height, "0px") If Me.ImageMiddleLeftURL.Trim.Length > 0 Then writer.AddStyleAttribute(HtmlTextWriterStyle.BackgroundImage, "url(" &Me.ImageMiddleLeftURL.Trim & ")") writer.AddStyleAttribute("background-repeat", "repeat-y") End If writer.RenderBeginTag(HtmlTextWriterTag.Td) writer.RenderEndTag() 'td
The above completes the creation of first cell. Now we create the second cell without closing it. I just open the middle cell with the “<td>” tag and don’t close it at all. This allows the developer to write his own content according to his needs. Then who will close the cell? The next section will explain that.
'middle middle (center) writer.AddAttribute(HtmlTextWriterAttribute.Width, "100%") writer.AddAttribute(HtmlTextWriterAttribute.Height, "100%") If Me.ImageMiddleMiddleURL.Trim.Length > 0 Then writer.AddStyleAttribute (HtmlTextWriterStyle.BackgroundImage, "url(" &Me.ImageMiddleMiddleURL.Trim & ")") End If writer.RenderBeginTag(HtmlTextWriterTag.Td)
You can look at the last statement. It only opens “<TD>” and does not close it yet.
In the previous section, we already opened the center cell. But we haven't closed it yet. In this section we are going to close it.
writer.RenderEndTag() 'td 'middle right writer.AddAttribute(HtmlTextWriterAttribute.Width, "0px") writer.AddAttribute(HtmlTextWriterAttribute.Height, "0px") If Me.ImageMiddleRightURL.Trim.Length > 0 Then writer.AddStyleAttribute (HtmlTextWriterStyle.BackgroundImage, "url(" &Me.ImageMiddleRightURL.Trim & ")") writer.AddStyleAttribute("background-repeat", "repeat-y") End If writer.RenderBeginTag(HtmlTextWriterTag.Td) writer.RenderEndTag() 'td writer.RenderEndTag() 'tr
The above is quite straightforward for closing the previously opened “<TD>” tag. But the above code is not part of the “RenderBeginTag” method. Instead, it is from the “RenderEndTag” method. We further proceed to create the footer row by adding the same type of code (with very few modifications) available in the “Creating the Header” section to the above code fragment. As the coding is quite similar, you can get it from the downloadable.
Everything until now is fine. How did I implement the trick to get the “developer specified content” into my control? This is from the following code fragment.
Protected Overrides Sub RenderContents(ByVal writer As System.Web.UI.HtmlTextWriter) writer.Write(Text) End Sub
Even though it is only three lines, it should be considered the heart of the control. In other words, when the control is getting rendered, it first executes the "RenderBeginTag” method followed by the “RenderContents” method and finally the “RenderEndTag.” For a detailed explanation of “rendereing” issues, I suggest you to refer my previous articles of the same series.
Even though I started emitting exclusive HTML using “writer” methods, you can also do the same by extending your control from an already existing “table” web control. If you directly extend it from the “table” web control, you can work with an almost .NET based ASP.NET framework model to add table rows and cells, which looks convenient and even readable. But in that case, we need to understand a bit about the “rendering” issues of child controls within the parent control.
I leave it to the developers for further enhancing this control. The areas of improving the it would include eventing, better JavaScript for validation, data-binding, and so on. Good luck.
Any comments, suggestions, bugs, errors, feedback etc. are highly appreciated at jag_chat@yahoo.com.