Published:
01 Apr 2003
|
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):
34354/
42
|
|
|
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
|
|