Is inheriting from Table a bad idea?

I have an ASP .NET composite server control that I've developed that uses a table as its base.  It works correctly at run-time, but at design-time I get some flaky behavior.  The first time the control renders on the design surface, everything looks good.  But if I change any of the control's properties, then I just get an empty table. This control does not allow the page developer to add new rows--it is basically a positioning container used for a variety of other UI elements that get rendered together.

I set a breakpoint in the RenderContents method.  The first line is a call to Me.EnsureChildControls, but CreateChildControls does not get called because Me.ChildControlsCreated is set to True. At runtime, this doesn't happen. The control renders correctly on every pass.  At design-time, I have this problem every time the control refreshes itself after changing a property value.

To test, I created a simple TestTable and got similar results.  Here's the source for that one:

Public Class TestTable

Inherits Table

Implements INamingContainer

Protected Overrides Function SaveViewState() As Object

Return MyBase.SaveViewState()

End Function

Protected Overrides Sub LoadViewState(ByVal savedState As Object)

MyBase.LoadViewState(savedState)

End Sub

Protected Overrides Sub TrackViewState()

MyBase.TrackViewState()

End Sub

Protected Overrides Sub CreateChildControls()

Me.Controls.Clear()

Dim tr As New TableRow

Dim tc As New TableCell

tr.Cells.Add(tc)

Me.Rows.Add(tr)

Dim lbl As New Label

lbl.Text = "Test"

tc.Controls.Add(lbl)

End Sub

Protected Overrides Sub RenderContents(ByVal writer As System.Web.UI.HtmlTextWriter)

Me.EnsureChildControls()

MyBase.RenderContents(writer)

End Sub

End Class

To run this test, just set your breakpoint on Me.EnsureChildControls.  The first time the control is rendered in design view, ChildControlsCreated = False, and the CreateChildControls() method gets called.  Change any property, and you'll break again; this time ChildControlsCreated will be True, and CreateChildControls() will not be called.

I could fix this in one of two ways that I know of: I could change the control so that it creates a DIV and creates the entire table on every postback; I could also modify RenderContents() as follows:

Protected Overrides Sub RenderContents(ByVal writer As System.Web.UI.HtmlTextWriter)

If Me.ChildControlsCreated And IsNothing(Me.Page.Session) Then

Me.ChildControlsCreated = False

End If

Me.EnsureChildControls()

MyBase.RenderContents(writer)

End Sub

This seems like a hack to me.  I'm wondering if anyone else has any different ideas.  Is there a reason why it might be a bad idea to inherit from table when I'm just using the table as a positioning element?  Is there something else I could do in my code to cause it to recreate the child controls in design mode?  If anyone has any better ideas, I'll update this post and properly credit you.

Thanks a lot!


UPDATE

Justin Lovell says:

Suggestion from your first code listing... change this line:

Me.EnsureChildControls()

To:

If (HttpContext.Current Is Nothing) Then
CreateChildControls()
Else
EnsureChildControls()

Andy Smith says:

“You shouldn't be deriving from Table when you make a composite control. Derive from WebControl and contain a table.“

Both of which I sort of already thought, as stated in my original post just above the second code sample.  Since what I was after at root was some validation that I was on the right track and wasn't overlooking anything obvious, I have to offer my thanks to Andy and Justin.  Thanks guys!

Published Monday, May 24, 2004 1:42 PM by taganov
Filed under:

Comments

# re: Is inheriting from Table a bad idea?

Monday, May 24, 2004 2:46 PM by Justin Lovell

Suggestion from your first code listing... change this line:

Me.EnsureChildControls()

To:

If (HttpContext.Current Is Nothing) Then
CreateChildControls()
Else
EnsureChildControls()
End If

# re: Is inheriting from Table a bad idea?

Monday, May 24, 2004 2:54 PM by Andy Smith

You shouldn't be deriving from Table when you make a composite control. Derive from WebControl and contain a table.

# re: Is inheriting from Table a bad idea?

Monday, May 24, 2004 3:11 PM by Chris McKenzie

You guys have both said sort of what I was thinking. I was looking for some validation that I hadn't missed something obvious. Thanks!

# re: Is inheriting from Table a bad idea?

Monday, May 24, 2004 4:09 PM by AndrewSeven

It seems like it is an issue with the designer, I made small custom designer and got it working (c#).
Are there specific reasons to use WebControl as the base for most/all composites?



using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Web;
using System.Web.SessionState;
using System.Web.UI;
using System.Web.UI.Design.WebControls;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;

using System.Text;
using System.IO;

namespace TemplatedSampleSite.aspmessageboard.Classes
{

public class TestTableDesigner : TableDesigner
{
override public string GetDesignTimeHtml()
{

Control c= ((Control)Component);
StringWriter sw = new StringWriter();
HtmlTextWriter tw = new HtmlTextWriter(sw);
///Key call to render control.
///The call to base.GetDesignTimeHtml()
/// will return "correct" markup as will sw.ToString();

c.RenderControl(tw);
//return sw.ToString();
return base.GetDesignTimeHtml();
}

}

[Designer(typeof(TestTableDesigner))]
public class TestTable : Table
{
protected override void CreateChildControls()
{

Controls.Clear();
TableRow tr = new TableRow();
TableCell tc = new TableCell();
tr.Cells.Add(tc);
Label label = new Label();
label.Text = "Test HERE";
tc.Controls.Add(label);
this.Rows.Add(tr);
}
protected override void RenderContents(HtmlTextWriter tw)
{
EnsureChildControls();
base.RenderContents(tw);
}
}

}

# re: Is inheriting from Table a bad idea?

Monday, May 24, 2004 4:26 PM by Chris McKenzie

Hi Andrew,
The Designer is a good idea :). The only problem I forsee with using a table as the basis for a composite control is that the page developer will have access to the "rows" property, and will be able to modify the contents of the control directly.

Leave a Comment

(required) 
(required) 
(optional)
(required)