As can be seen in the screen shot, the result is no error, no warning, no table. The markup supplied to the page is as follows:
<span id="WebCustomControl1_1"><teble><tr><td>Name: </td><td>Frank</td></tr><tr><td>Name: </td><td>Jessie</td></tr><tr><td>Name: </td><td>Wyatt</td></tr></table></span>
In contrast, to render out the same table using the HtmlTextWriter as I believe it was intended to be used results in this code:
'start the table
output.RenderBeginTag(HtmlTextWriterTag.Table)
'start the row
output.RenderBeginTag(HtmlTextWriterTag.Tr)
'add data
output.RenderBeginTag(HtmlTextWriterTag.Td)
output.Write("Name: ")
output.RenderEndTag()
output.RenderBeginTag(HtmlTextWriterTag.Td)
output.Write("Freddie")
output.RenderEndTag()
'end the row
output.RenderEndTag()
'start the row
output.RenderBeginTag(HtmlTextWriterTag.Tr)
'add data
output.RenderBeginTag(HtmlTextWriterTag.Td)
output.Write("Name: ")
output.RenderEndTag()
output.RenderBeginTag(HtmlTextWriterTag.Td)
output.Write("Jason")
output.RenderEndTag()
'end the row
output.RenderEndTag()
'start the row
output.RenderBeginTag(HtmlTextWriterTag.Tr)
'add data
output.RenderBeginTag(HtmlTextWriterTag.Td)
output.Write("Name: ")
output.RenderEndTag()
output.RenderBeginTag(HtmlTextWriterTag.Td)
output.Write("Leatherface")
output.RenderEndTag()
'end the row
output.RenderEndTag()
'end the table
output.RenderEndTag()
As you can see, there are more lines of code associated with this type of use of the class, however, it is safer. In fact, if you were to try to introduce the same error, you'd find that you will not get very far

In the image above, you see that the error is highlighted and this error will prevent building the control as indicated in the next figure.

It may also be interesting to note that the source for the page is more properly formed without any additional effort:
<span id="WebCustomControl1_1"><table>
<tr>
<td>Name: </td><td>Freddie</td>
</tr><tr>
<td>Name: </td><td>Jason</td>
</tr><tr>
<td>Name: </td><td>Leatherface</td>
</tr>
</table></span>
Note that the web control is placed into a span as is the default behavior. The beginning tag can be overridden in the control by overriding a read only property called TagKey. After overriding the TagKey property with a table tag, the page source will be as follows: (Note the span is gone and the control is started with the table tag)
<table id="WebCustomControl1_1">
<tr>
<td>Name: </td><td>Freddie</td>
</tr><tr>
<td>Name: </td><td>Jason</td>
</tr><tr>
<td>Name: </td><td>Leatherface</td>
</tr>
</table>
The code to override the TagKey to use the table tag is as follows:
Protected Overrides ReadOnly Property TagKey() As System.Web.UI.HtmlTextWriterTag
Get
Return HtmlTextWriterTag.Table
End Get
End Property
Of course after making this change, the code used to render the control should be modified by dropping the table related beginning and ending tags and just starting off with the first row tag. If you overrode the TagKey property with a div tag, you would still need to add the beginning and ending table tags. The page source for that would end up looking like this:
<div>
<div id="WebCustomControl1_1">
<table>
<tr>
<td>Name: </td><td>Freddie</td>
</tr><tr>
<td>Name: </td><td>Jason</td>
</tr><tr>
<td>Name: </td><td>Leatherface</td>
</tr>
</table>
</div>
</div>
Adding Attributes
It is possible to add attributes to the control's HTML through the use of the HtmlTextWriter class. Attributes added with the HtmlTextWriter need to be added in advance of a beginning tag. For example:
'start the table
output.AddAttribute(HtmlTextWriterAttribute.Border, "2")
output.AddAttribute(HtmlTextWriterAttribute.Cellpadding, "3")
output.RenderBeginTag(HtmlTextWriterTag.Table)
'start the row
output.RenderBeginTag(HtmlTextWriterTag.Tr)
'add data
output.AddAttribute(HtmlTextWriterAttribute.Align, "left")
output.RenderBeginTag(HtmlTextWriterTag.Td)
output.Write("Name: ")
output.RenderEndTag() ...
In looking at the example note that, prior to the beginning table tag, the HtmlTextWriter's AddAttribute method was called. AddAttribute is looking for an HtmlTextWriterAttribute tag and a value to associate with the tag. The example passes a tag (e.g., HtmlTextWriterAttribute.Border) and a value for the tag ("2"). It is possible to create an error here, for example, one could to pass value of "A" in lieu of "2" to the border.
Adding Styles
As with attributes, styles may be added using the HtmlTextWriter class, and also as with attributes, the style attributes need to be added in advance of the beginning tag for the targeted item. Style attributes are added with the HtmlTextWriter's AddStyleAttribute method. This method accepts two arguments as did the AddAttribute method. The first argument is the style and the second argument is the value.
In the example below, the table has the font size set to "Large" and the width of the table is set to 100%.
'start the table
output.AddStyleAttribute(HtmlTextWriterStyle.FontSize, "Large")
output.AddStyleAttribute(HtmlTextWriterStyle.Width, "100%")
output.AddAttribute(HtmlTextWriterAttribute.Alt, "Its a table")
output.AddAttribute(HtmlTextWriterAttribute.Border, "2")
output.AddAttribute(HtmlTextWriterAttribute.Cellpadding, "3")
output.RenderBeginTag(HtmlTextWriterTag.Table)
'start the row
output.RenderBeginTag(HtmlTextWriterTag.Tr)
The page source shows the style attributes added to the table:
<div id="WebCustomControl1_1">
<table alt="Its a table" border="2" cellpadding="3" style="font-size:Large;width:100%;">
<tr>
<td align="left">Name: </td><td align="left">Freddie</td>
</tr><tr>
<td>Name: </td><td>Jason</td>
</tr><tr>
<td>Name: </td><td>Leatherface</td>
</tr>
</table>
</div>
Adding Controls
The HtmlTextWriter may also be used to add subordinate controls to the custom control. The following examples show adding different objects to the custom control through the use of object's RenderControl method.
Adding an image:
output.AddAttribute(HtmlTextWriterAttribute.Align, "center")
output.RenderBeginTag(HtmlTextWriterTag.Tr)
output.RenderBeginTag(HtmlTextWriterTag.Td)
Dim img As New Image()
img.ImageUrl = SourceImg.ToString()
img.BorderStyle = WebControls.BorderStyle.Inset
img.BorderWidth = 2
img.RenderControl(output)
output.RenderEndTag()
output.RenderEndTag()
Adding a text box:
output.RenderBeginTag(HtmlTextWriterTag.Td)
output.AddStyleAttribute(HtmlTextWriterStyle.FontFamily, Me.Font.Name)
output.AddAttribute(HtmlTextWriterAttribute.Size, _
Me.Font.Size.ToString())
txtAmount.RenderControl(output)
output.RenderEndTag()
Adding a button:
output.RenderBeginTag(HtmlTextWriterTag.Td)
output.AddStyleAttribute(HtmlTextWriterStyle.FontFamily, Me.Font.Name)
output.AddAttribute(HtmlTextWriterAttribute.Size, _
Me.Font.Size.ToString())
btnSubmit.RenderControl(output)
output.RenderEndTag()
With the exception of the image in the first example, each of the objects would likely be instantiated in the overridden CreateChildControls subroutine; from there the control could have its properties set and could have event handlers added to the instance. The controls are then also added to the control collection. In this case, the RenderContents method merely places the existing controls. Having said that, the image example provided first shows the creation of the image within the RenderContents subroutine.
The following example illustrates adding a creating button in the CreateChildControls subroutine; in the example, the button is created, its text property is set, and the click event handler is added to the button; the button is then added to the control collection:
' creats the submit button and assigns it a handler
btnSubmit = New Button
btnSubmit.Text = "Submit"
AddHandler btnSubmit.Click, AddressOf btnSubmit_Click
Me.Controls.Add(btnSubmit)
Using the same approach indicated in the examples, one could add other types of subordinate controls to the custom control.
Summary
This article was intended to provide a brief introduction to the HtmlTextWriter class in the context of using it to render custom controls. This is not an all encompassing description of the class and it does define all of the things that you can through the class. The intent was to provide a sufficient introduction to the topic to allow one to use the class to define an interface for a custom control.