Custom Control Designers : Design-time HTML
 
Published: 01 Apr 2003
Unedited - Community Contributed
Abstract
You may have noticed that when you import a custom control into VS.NET, it displays an error where the control is. This is because you have not supplied any HTML code for it to render. This article descibes how to render HTML for the preview in VS.NET
by . .
Feedback
Average Rating: This article has not yet been rated.
Views (Total / Last 10 Days): 38165/ 100

Introduction

Introduction

In my previous articles, you may have noticed that when you import a control into VS.NET, it displays an error where the control is. This is because you have not supplied any HTML code for it to render.

The .NET Framework provides a special class for the design-time HTML and this article will show you how to utilize that class to render HTML when using a custom control in VS.NET.

You can find the complete code and compiled assembly at the end of this article.

The Class

The Class

The designer class, is not part of the Control or Webcontrol classes and therefore is slightly different in terms of implementation.

The class that contains the functionality is the System.Web.UI.Design.ControlDesigner class which provides several functions, which aid in providing the design-time HTML.

If you are using VS.NET, remember to add a reference to System.Design.dll so that you can see this class (as it is not contained within System.Web.dll).

Current Code

The code that will be used for the rest of this article, will be the Multi-Highlighter custom control and we will be improving it upon.

Public Class DesignerSample
Inherits System.Web.UI.WebControls.WebControl
Implements IPostBackEventHandler

Private _Text() As String = {""}

<Category("Misc"), _
Description("Specifies the text to be displayed."), _
Browsable(
True)> _
Public Property Text() As String()
Get
Return
_Text
End Get
Set(ByVal Value() As String)
_Text = Value
End Set
End Property

Protected Overrides Sub Render(ByVal output As System.Web.UI.HtmlTextWriter)
Dim i
output.AddAttribute("border", "1")
output.AddStyleAttribute("cursor", "hand")
output.AddStyleAttribute("border-width", "1")
output.AddStyleAttribute("border-color", "#000000")
output.RenderBeginTag("table")
For i = 0 To Text.GetUpperBound(0)
output.AddAttribute("onClick", Page.GetPostBackEventReference(
Me, i))
If ViewState(ID & i) = 1 Then
output.AddAttribute("bgcolor", "#85FF72")
Else
output.AddAttribute("bgcolor", "#FFFFFF")
End If
output.RenderBeginTag("tr")
output.RenderBeginTag("td")
output.AddAttribute("face", "Arial")
output.AddAttribute("size", "2")
output.RenderBeginTag("font")
output.Write(Text(i))
output.RenderEndTag()
output.RenderEndTag()
output.RenderEndTag()
Next
output.RenderEndTag()
End Sub

Public Sub PostBackEvent(ByVal eventargs As String) Implements IPostBackEventHandler.RaisePostBackEvent
If ViewState(ID & eventargs) = 1 Then
ViewState(ID & eventargs) = 0
Else
ViewState(ID & eventargs) = 1
End If
End Sub
End
Class

You may see in the code that the Text field is now exposed as a property with design-time attributes and _Text is initialized.

The ControlDesigner

The ControlDesigner

The ControlDesigner class has several functions, which we will be using which I will go over briefly now.
 

  • GetDesignTimeHTML - This function returns a string of HTML,
    This is used by VS.NET (or other host) to render the control at design-time.

  • GetEmptyDesignTimeHTML - This function returns no HTML or HTML
    for an empty control (I will go over this in more depth later.

  • GetErrorDesignTimeHTML - This function returns the HTML to
    render when there is an error in displaying one of the other two. The
    default is the standard error message (which I'm sure you've seen).

Implementing the ControlDesigner

Implementing the ControlDesigner

Now for some action! Below is the code for the class, which will be used to provide HTML.
 

Public Class DesignerHtml
Inherits System.Web.UI.Design.ControlDesigner

Public Overrides Function GetDesignTimeHTML() As String
Dim
controltext() As String = CType(Component, DesignerSample).Text

If
controltext.GetUpperBound(0) >= 1 Then
Dim
writer As New System.IO.StringWriter()
Dim html As New HtmlTextWriter(writer)
Dim tbl As New HtmlTable()
tbl.Border = 1
tbl.Style.Add("cursor", "hand")
tbl.Style.Add("border-width", "1")
tbl.Style.Add("border-color", "#000000")
Dim tr
Dim td
Dim i As Integer
For
i = 0 To controltext.GetUpperBound(0)
tr = New HtmlTableRow()
td = New HtmlTableCell()
tr.Style.Add("bgcolor", "#FFFFFF")
td.InnerText = controltext(i)
tr.Controls.Add(td)
tbl.Controls.Add(tr)
Next
tbl.RenderControl(html)
Return writer.ToString()
Else
Return
GetEmptyDesignTimeHtml()
End If

End
Function
End Class

You can see that this class simply inherits from ControlDesigner and overrides one of its functions - GetDesignTimeHTML().

The code for this function looks similar to the code for the actual render method for the Multi-Highlight control and it is. You can see that we use a StringWriter (to get our HTML as a string) and an HTMLTextWriter (to store our HTML) to hold and return the code.

We also use a series of HTML controls (HtmlTable, HtmlTableRow and HtmlTableCell) to build the table and then render it out.

You will notice that the PostBack code is missing (as described in this article), this is because the PostBack would not work well in a designer. The code provided here should only be a raw template or placeholder for the user to see the placement and possible size of the control (among other things), but it is not designed to provide total functionality of the control.

In the code I use -
Dim controltext() as String = CType(Component, DesignerSample).Text - this gets the text of our Multi-Highlighter (this is in a class called DesignerSample in this example). The Component (in the code) is an instance of the control (or component) that this designer is associated with (as you will see later).

Finally, you will notice that I use GetEmptyDesignTimeHTML() without overriding it, this will provide the default HTML (nothing).

Problems

The Problem

The problem with this code is the controltext array. The problem is that this array is not assigned at design-time and it is assigned at run-time (although this can be changed). To fix this, we will have to use a static array for our code -

Dim controltext() As String = {"[Sample 1]", "[Sample 2]", "[Sample 3]"}

Although this is not an actual rendering of the control, it does provide what we want to achieve -

  • A hint at what the control may/will look like

  • The approximate size of the control

  • The design and style of the control

Later in this article we will be adding a more dynamic feel to the control.

The Finished Control

The Actual Control

None of this will work, without the all-important control. Below is some of the code for the control.

<Designer("AGASPCC.DesignerHtml, AGASPCC")> _
Public
Class DesignerSample
Inherits System.Web.UI.WebControls.WebControl
Implements IPostBackEventHandler

Private
_Text() As String
= {""}
.....

This is the only change that needs to be made to the class at this moment.

The Designer attribute takes one parameter - the fully qualified class name and location. In case you have no idea what this means, think of it
like -

[Class Location], [Namespace]

For example -

MyNamespace.MySubNamespace.MyClass, MyNamespace.MySubNamespace

Now, if you combine the code from before (with the static array) with this code (all is available at the end of the article if you're confused) then you should have a working sample (and no error message).

Making it Dynamic

Making it Dynamic

So far, this code has produced a static sample. The reason is that the code for setting the Text property is set in the Page_Load method because it is an array. Here, we will add it to the Property Inspector so you can enter an array, change the code to be dynamic and make a static version.

We do not need to make any modifications to our DesignerSample class because we already made them. It is important to remember that because we're dealing with an array, we must initialize it or we will get an error in VS.NET.

Now, I want to make it dynamic, but just incase they don't enter anything into the Text property, we will have a back up - our current code.
 

Public Class DesignerHtml
Inherits System.Web.UI.Design.ControlDesigner

Public Overrides Function GetDesignTimeHTML() As String
Dim
controltext() As String = CType(Component, DesignerSample).Text

If
controltext.GetUpperBound(0) >= 1 Then
Dim
writer As New System.IO.StringWriter()
Dim html As New HtmlTextWriter(writer)
Dim tbl As New HtmlTable()
tbl.Border = 1
tbl.Style.Add("cursor", "hand")
tbl.Style.Add("border-width", "1")
tbl.Style.Add("border-color", "#000000")
Dim tr
Dim td
Dim i As Integer
For
i = 0 To controltext.GetUpperBound(0)
tr = New HtmlTableRow()
td = New HtmlTableCell()
tr.Style.Add("bgcolor", "#FFFFFF")
td.InnerText = controltext(i)
tr.Controls.Add(td)
tbl.Controls.Add(tr)
Next
tbl.RenderControl(html)
Return writer.ToString()
Else
Return
GetEmptyDesignTimeHtml()
End If
End
Function

Protected
Overrides Function GetEmptyDesignTimeHtml() As String
Dim controltext() As String = {"[Sample 1]", "[Sample 2]", "[Sample 3]"}

Dim writer As New System.IO.StringWriter()
Dim html As New HtmlTextWriter(writer)
Dim tbl As New HtmlTable()
tbl.Border = 1
tbl.Style.Add("cursor", "hand")
tbl.Style.Add("border-width", "1")
tbl.Style.Add("border-color", "#000000")
Dim tr
Dim td
Dim i As Integer
For i = 0 To controltext.GetUpperBound(0)
tr =
New HtmlTableRow()
td =
New HtmlTableCell()
tr.Style.Add("bgcolor", "#FFFFFF")
td.InnerText = controltext(i)
tr.Controls.Add(td)
tbl.Controls.Add(tr)
Next
tbl.RenderControl(html)
Return writer.ToString()
End Function

End Class

All that changed was that I removed the If statement and it now overrides GetEmptyDesignTimeHTML() instead of GetDesigntimeHTML().

Also we shifted the array back to it's previous way (of being dynamic) while providing a safety net if it does not work out as planned.

The Final Result

The final

If you compile this code and use it in VS.NET you will see that you have a control that shows you almost exactly what the control will look like (even if you do not give it any text).

Without Text -

With Text -

Note that because you are dealing with an array you can get the collection editor by clicking the "..." next to the field -



Summary

This article went quite deep into designers and how to use a simple one like HTML rendering to get a working effect.

You may be able to tell that this is not the end for custom control designers (Part 1) as there is much more code that can be done (take a look at the DataGrid's designer for example) and I will be providing this code and information in future articles.

Code for this article.

The code for this article comes in two methods - TXT file and RAR archive. The TXT file is a plain text file of the classes in this article and the RAR contains a compiled assembly and TXT file of the classes.

Static Multi-Highlighter - TXT
Dynamic Multi-Highlighter - TXT
Assembly and source - RAR

All RAR files need to be extracted with WinRAR 3.0 (or above) see http://www.rarlabs.com/ to get it.



User Comments

No comments posted yet.

Product Spotlight
Product Spotlight 





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


©Copyright 1998-2019 ASPAlliance.com  |  Page Processed at 2019-04-19 2:31:13 PM  AspAlliance Recent Articles RSS Feed
About ASPAlliance | Newsgroups | Advertise | Authors | Email Lists | Feedback | Link To Us | Privacy | Search