How do I access ASP.NET ITemplate Container Properties

125 views Asked by At

I'm trying to learn how to use ITemplate for nicer custom controls. I have it mostly working but I haven't been able to figure out how to access any properties of the container from the page.

Here is my templated control:

[ParseChildren(true)]
[PersistChildren(false)]
public partial class Example : UserControl
{
    private ITemplate _CustomPanelContainer;

    [PersistenceMode(PersistenceMode.InnerProperty)]
    [TemplateContainer(typeof(CustomPanelContainer))]
    [TemplateInstance(TemplateInstance.Single)]
    public virtual ITemplate CustomPanel
    {
        get { return _CustomPanelContainer; }
        set { _CustomPanelContainer = value; }
        
    }


    protected override void CreateChildControls()
    {
        Controls.Clear();
        if (_CustomPanelContainer != null)
        {
            var p = new Panel();
            p.ID = "CustomPanel";
            Controls.Add(p);
            _CustomPanelContainer.InstantiateIn(p);
        }
        base.CreateChildControls();
    }


    public class CustomPanelContainer : Panel, INamingContainer 
    {
        
        private string _Test = "TESTING!";
        public string TextTest 
        { 
            get 
            { 
                return _Test;
            }
            set
            {
                _Test = value;
            }
        }
    }
}

Here is the page implementation:

<uc1:Example runat="server" ID="Example1">
        <CustomPanel>
            <strong>Test: </strong> <%# Container.TextTest %>
        </CustomPanel>
    </uc1:Example>

It is mostly working but the problem is that <%# Container.TextTest %> always returns an empty string. When I run it on the debugger, I put a breakpoint at the line inside the TextTest property of CustomPanelContainer and the breakpoint is never hit, so the property is never actually being accessed.

What am I missing here? How do I enable access to the container's public properties via <%#Container ?

1

There are 1 answers

0
Plumbtrician On

I finally figured out how to make it act the way I want.

I removed ITemplate as the type of the Container and set the type as the actual type and added a DataBind() command to CreateChildControls().

Maybe not quite the correct way to do this, but it works.

Keeping the question open for a bit to see if anyone offers any critique or a better approach, since I really don't know what I'm doing here yet.

Simplified Working code:

[ParseChildren(true)]
[PersistChildren(false)]
public partial class Example : UserControl
{

    [PersistenceMode(PersistenceMode.InnerProperty)]
    [TemplateInstance(TemplateInstance.Single)]
    public virtual CustomPanelContainer Template { get; set; }


    protected override void CreateChildControls()
    {
        Controls.Clear();
        if (Template != null)
        {
            Template.DataBind();
            Controls.Add(Template);
        }
        base.CreateChildControls();
    }

    

    public class CustomPanelContainer : Panel, INamingContainer
    {
        public string TextTest
        {
            get { return "TESTING!"; }
        }
    }
}

Page Implementation:

<uc1:Example runat="server" ID="Example">
    <Template>
        <strong>Test: </strong><span><%# Container.TextTest %></span>
    </Template>
</uc1:Example>

EDIT: This also works when needing to hide the type of the template. i,e., the code above exposes the type of Template to allow manipulating properties of the Panel as attributes of Template, whereas the code below hides the type of Template to block manipulation of its properties.

[ParseChildren(true)]
[PersistChildren(false)]
public partial class Example : UserControl
{

    [PersistenceMode(PersistenceMode.InnerProperty)]
    [TemplateInstance(TemplateInstance.Single)]
    [TemplateContainer(typeof(CustomPanelContainer))]
    public virtual ITemplate Template { get; set; }


    protected override void CreateChildControls()
    {
        Controls.Clear();
        if (Template != null)
        {
            var p = new CustomPanelContainer();
            Template.InstantiateIn(p);
            p.DataBind();
            Controls.Add(p);
        }
        base.CreateChildControls();
    }

    

    public class CustomPanelContainer : Panel, INamingContainer
    {
        public string TextTest
        {
            get { return "TESTING!"; }
        }
    }