ASP.NET WebControl ITemplate child controls are null

Posted by tster on Stack Overflow See other posts from Stack Overflow or by tster
Published on 2010-04-17T14:25:34Z Indexed on 2010/04/17 14:33 UTC
Read the original article Hit count: 592

Filed under:
|
|

Here is what I want:

I want a control to put on a page, which other developers can place form elements inside of to display the entities that my control is searching. I have the Searching logic all working. The control builds custom search fields and performs searches based on declarative C# classes implementing my SearchSpec interface.

Here is what I've been trying:

I've tried using ITemplate on a WebControl which implements INamingContainer I've tried implementing a CompositeControl

The closest I can get to working is below.

OK I have a custom WebControl

[
AspNetHostingPermission(SecurityAction.Demand, Level = AspNetHostingPermissionLevel.Minimal),
AspNetHostingPermission(SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal),
DefaultProperty("SearchSpecName"),
ParseChildren(true),
ToolboxData("<{0}:SearchPage runat=\"server\"> </{0}:SearchPage>")
]
public class SearchPage : WebControl, INamingContainer
{

    [Browsable(false),
    PersistenceMode(PersistenceMode.InnerProperty),
    DefaultValue(typeof(ITemplate), ""),
    Description("Form template"),
    TemplateInstance(TemplateInstance.Single),
    TemplateContainer(typeof(FormContainer))]
    public ITemplate FormTemplate { get; set; }

    public class FormContainer : Control, INamingContainer{ }

    public Control MyTemplateContainer { get; private set; }

    [Bindable(true), Category("Behavior"), DefaultValue(""),
     Description("The class name of the SearchSpec to use."), Localizable(false)]
    public virtual string SearchSpecName
    {
        get;
        set;
    }

    [Bindable(true), Category("Behavior"), DefaultValue(true), 
    Description("True if this is query mode."), Localizable(false)]
    public virtual bool QueryMode
    {
        get;
        set;
    }

    private SearchSpec _spec;
    private SearchSpec Spec
    {
        get
        {
            if (_spec == null)
            {
                Type type = Assembly.GetExecutingAssembly().GetTypes().Where(t => t.Name == SearchSpecName).First();
                _spec = (SearchSpec)Assembly.GetExecutingAssembly().CreateInstance(type.Namespace + "." + type.Name);
            }
            return _spec;
        }
    }

    protected override void CreateChildControls()
    {
        if (FormTemplate != null)
        {
            MyTemplateContainer = new FormTemplateContainer(this);
            FormTemplate.InstantiateIn(MyTemplateContainer);
            Controls.Add(MyTemplateContainer);
        }
        else
        {
            Controls.Add(new LiteralControl("blah"));
        }

    }

    protected override void RenderContents(HtmlTextWriter writer)
    {
        // <snip>
    }


    protected override HtmlTextWriterTag TagKey
    {
        get
        {
            return HtmlTextWriterTag.Div;
        }
    }

}

public class FormTemplateContainer : Control, INamingContainer
{
    private SearchPage parent;
    public FormTemplateContainer(SearchPage parent)
    {
        this.parent = parent;
    }
}

then the usage:

<tster:SearchPage ID="sp1" runat="server" SearchSpecName="TestSearchSpec" QueryMode="False">
 <FormTemplate>
    <br />
    Test Name:
    <asp:TextBox ID="testNameBox" runat="server" Width="432px"></asp:TextBox>
    <br />
    Owner:
    <asp:TextBox ID="ownerBox" runat="server" Width="427px"></asp:TextBox>
    <br />
    Description:
    <asp:TextBox ID="descriptionBox" runat="server" Height="123px" Width="432px" 
        TextMode="MultiLine" Wrap="true"></asp:TextBox>
 </FormTemplate>
</tster:SearchPage>

The problem is that in the CodeBehind, the page has members descriptionBox, ownerBox and testNameBox. However, they are all null. Furthermore, FindControl("ownerBox") returns null as does this.sp1.FindControl("ownerBox"). I have to do this.sp1.MyTemplateContainer.FindControl("ownerBox") to get the control.

How can I make it so that the C# Code Behind will have the controls generated and not null in my Page_Load event so that developers can just do this:

testNameBox.Text = "foo";
ownerBox.Text = "bar";
descriptionBox.Text = "baz";

© Stack Overflow or respective owner

Related posts about ASP.NET

Related posts about c#