Library code snippets

Dynamically loading an IBindableTemplate

In ASP.NET 1.x, when using a templated control, we have a choice between specifying these templates inline, or loading them dynamically using the LoadTemplate method. This would allow us to load an .ascx file and get an implementation of the ITemplate interface which we could then assign to the desired template on the server control.

In ASP.NET 2.0 this obviously still applies, but there's a caveat - if you want to take advantage of the new two-way binding features in controls such as the new FormView control, you can only specify the templates inline. The reason for this is that in order to provide the two-way binding, ASP.NET needs to generate some behind the scene code in order to implement a new IBindableTemplate interface - just as the ITemplate was used previously. Unfortunately, the ASP.NET team didn't get time to implement an equivalent LoadBindableTemplate method to fetch an implementation of IBindableTemplate - and so the only situation in which ASP.NET generates the required code is for the inline scenario.

The Workaround

So, what can we do? Well, the best workaround that I've been able to come up with goes as follows. In the .ascx file we're wanting to load our template from, instead of just providing the contents of the template, we wrap it within an <ItemTemplate> tag of a FormView or any other two-way bindable control, such as this:

<%@ Control %>
<asp:FormView runat="server">
  <ItemTemplate>
   <asp:TextBox runat="server" Text=<%# Bind("UserName") %> />
 </ItemTemplate>
</asp:FormView>

This means that when we load this control (using the standard LoadControl function), ASP.NET will have generated the required code and implemented IBindableTemplate for us. We can then use the following code:

public IBindableTemplate LoadBindableTemplate(string path) {
Control c = Page.LoadControl(path);
FormView fv = c.Controls[0] as FormView;
if (fv==null)
throw new Exception("Required FormView control not found as the first child of specified template");
return (IBindableTemplate)fv.ItemTemplate;
}

Then we can simply use this as we'd have used LoadTemplate (note you need to do this no later than the OnInit event), on the FormView object (in this case, called myFormView) that we wanted to dynamically load the template for.

myFormView.EditItemTemplate = LoadBindableTemplate("/myBindableTemplate.ascx");

Combining Templates

We can also now consider doing things such as combining two templates into one - for example, loading a common set of input fields from one template, and dynamically loading a second from elsewhere. To do this, we create a class that implements IBindableTemplate, and takes two IBindableTemplate implementations in the constructor.

public class JointBindableTemplate : IBindableTemplate
{
    IBindableTemplate _firstTemplate;
    IBindableTemplate _secondTemplate;

    public JointBindableTemplate(IBindableTemplate firstTemplate, IBindableTemplate secondTemplate)
    {
        this._firstTemplate = firstTemplate;
        this._secondTemplate = secondTemplate;
    }
    public IOrderedDictionary ExtractValues(Control container)
    {
        // extract the values for each of the templates
        IOrderedDictionary d1 = _firstTemplate.ExtractValues(container);
        IOrderedDictionary d2 = _secondTemplate.ExtractValues(container);
        // copy over to the second collection
        foreach (object key in d1.Keys)
            d2.Add(key, d1[key]);
        // return the combined collection
        return d2;
    }

    public void InstantiateIn(Control container)
    {

        // create a container control
        Control c = new Control();
        // instantiate the two templates into this control
        _firstTemplate.InstantiateIn(c);
        _secondTemplate.InstantiateIn(c);
        // add our control to the container we were passed
        container.Controls.Add(c);
    }
}

We can then use the following:

IBindableTemplate t1 = LoadBindableTemplate("/myCommonTemplate.ascx");
IBindableTemplate t2 = LoadBindableTemplate("/myExtendedTemplate.ascx"); 
JointBindableTemplate c = new JointBindableTemplate(t1,t2);
myFormView.EditItemTemplate = c;

Voila! If anyone has any comments on this - or knows a better workaround, then please let me know.

Comments

  1. 16 Nov 2006 at 12:31
    Great article! Thank you very much.

  2. 07 Sep 2006 at 10:27
    Many thanx for the post.

    Just looking for more detailed stuff on this. Or, if you can provide any working sample is also great.

    Regards





  3. 15 May 2006 at 15:52

    please disregrad my last post - I figured out the problem with my implentation.

    Again thanks for your article!

    I wish that MS would have provided a more robust two-way binding api   

     

     

     

  4. 11 May 2006 at 17:26

    This is exactly what I was looking for -thanks !

    would you happen to have a working example you could post?

  5. 01 Jan 1999 at 00:00

    This thread is for discussions of Dynamically loading an IBindableTemplate.

Leave a comment

Sign in or Join us (it's free).

James Crowley James first started this website when learning Visual Basic back in 1999 whilst studying his GCSEs. The site grew steadily over the years while being run as a hobby - to a regular monthly audience ...
AddThis

Related podcasts

Events coming up

  • Jul 7

    DTC 70-528 Session 7: Chapter 12

    Greenwood Village, United States

    Due to lack of interest of the 5th Monday meetup, we will continue as originally scheduled. The topic of the night will be "Chapter 12 - Creating ASP.NET Mobile Web Applications", taught by RJ Hatch. It is a fairly small chapter, so we can discuss other topics as well. Pizza and beverages will be provided on a donation basis.

Want to stay in touch with what's going on? Follow us on twitter!