Adding layout elements within custom control

P

paul.hester

Hi all,

I have a custom control that I use within forms that contains form
inputs and validator controls. At the moment I'm overriding the Render
method of my custom control and using the HtmlTextWriter object to
render the layout elements and the Control.RenderControl method in the
appropriate places to render the child controls in the right place.

I've run into a problem where literal content (i.e. <%= SomeVariable
%>) is not being rendered, and from what I can understand, it's because
of the way I'm rendering the child controls.

Could someone please advise me of the best way to add layout elements
around the child controls and with the literal content intact? Do I
need to override another method and add the extra layout elements to
the Controls collection?

Thanks,

Paul
 
A

Alessandro Zifiglio

hi Paul, Somethings you want to know when nesting controls in this manner is
:
1. Make sure you set the attribute ParseChildren(false) which is the
default, and is not necessary if you inherit the Control class, but for eg.
if you should inherit the webcontrols class then this is true by, you want
to reset it to false.

2. Try to associate a ControlBuilder, in this way you can limit the kind of
controls that are permitted as child controls. This is because you are going
to be testing for the control type in the AddParsedSubObject method, so a
control type that is not supported wont get added into the controls
collection, and will throw an error.

3. For inline code block expressions syntax <%= %>, i was unable to get the
value. In effect AddParsedSubObject is not even called. Futher digging in
the default ControlBUilder class shows that for this type of code blocks, it
is not handled by the controlbuilder and there you go. I was however able to
efficiently get the value of databinding expression syntax<%# %> after the
databinding phase through the controls the controls collection. This is
handled by the ControlBuilder class and AddParsedSubOjbect fires accurately.
If you have difficulty with this and need to see some working code, let me
know.

4. Also when using inline code block expressions syntax <%= %>, the
framework wont allow you to add controls other than the controls already
present as child Controls nested declaratively. So if you need to add more
content you will be overriding the render method as you are currently doing
and as i am doing in the following sample code below.

5. The key method you are looking for is AddParsedSubObject
Follows is working sample code.

Regards,
Alessandro Zifiglio
http://www.AsyncUI.net


<%@ Page Language="C#" %>
<%@ Register Assembly="ControlTestCenter" Namespace="ControlTestCenter"
TagPrefix="cc1" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<script runat="server">
string blah = "dood";
protected void Page_Load(object sender, EventArgs e)
{

}
</script>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>Untitled Page</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<cc1:MyCustomControl ID="MyCustomControl1" runat="server">
<asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
<asp:RequiredFieldValidator Display="dynamic"
ID="RequiredFieldValidator1" ControlToValidate="TextBox1" runat="server"
ErrorMessage="Textbox1 is required!"></asp:RequiredFieldValidator>
<%= blah %>
<asp:Button ID="Button1" Text="click me" runat="server" />
</cc1:MyCustomControl>
</div>
</form>
</body>
</html>


////////////////////////////////
////The custom control :
//////////////////////////////

using System;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Collections;
using System.Drawing;
namespace ControlTestCenter
{


public class MyControlBuilder : ControlBuilder
{

public override Type GetChildControlType(string tagName, IDictionary
attribs)
{
if (String.Compare(tagName, "asp:TextBox", true) == 0)
return typeof(TextBox);
else if (string.Compare(tagName, "asp:RequiredFieldValidator",
true) == 0)
return typeof(RequiredFieldValidator);
else if (string.Compare(tagName, "asp:Button", true) == 0)
return typeof(Button);

throw new Exception("The control you nested is not supported");
}

}
[ControlBuilderAttribute(typeof(MyControlBuilder))]
[ParseChildren(false)]
public class MyCustomControl : Control, INamingContainer
{
// Called at runtime when a child object is added to the collection.
protected override void AddParsedSubObject(object obj)
{
string s = obj.GetType().ToString();
if (obj is TextBox)
{
TextBox tb = (TextBox)obj;
Controls.Add(tb);
}
else if (obj is RequiredFieldValidator)
{
RequiredFieldValidator rFV = (RequiredFieldValidator)obj;
Controls.Add(rFV);
}
else if (obj is Button)
{
Button b = (Button)obj;
Controls.Add(b);
}

}

protected override void Render(HtmlTextWriter writer)
{

base.Render(writer);
writer.Write("this is working, nicely and maintains layout!");
}
}
}
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,013
Latest member
KatriceSwa

Latest Threads

Top