LoadTemplate and the ASP.NET Login controls

Recently I was trying to programmatically load the templates for the PasswordRecovery control. I thought it should be pretty straightforward:

  • Put the contents of the template in an ascx file
  • Assign passwordRecovery.UserNameTemplate to Page.LoadTemplate(“MyUserNameTemplate.ascx”)

Should be a piece of cake right? Wrong.

If the template is put directly in the ASPX page all works as expected.  If the same template is loaded using LoadTemplate, you’ll get an error like:

UserNameTemplate does not contain an IEditableTextControl with ID UserName for the username

After some sleuthing I realized the problem was in the way LoadTemplate adds the loaded template controls.  LoadTemplate (which returns an ITemplate of type SimpleTemplate) adds the loaded template to a parent control, and then adds that parent control to the container.  The login controls search the container for the required controls using FindControl. Since the container only contains the parent control, the required controls (which are in the parent control) are not found.

The solution was to create my own class derived from ITemplate.  The class loads the template into a temporary container using the LoadTemplate method.  Then it moves the child controls from the parent control in the temporary container into the destination container. Here’s the code:

/// <summary> 
/// Loads a template from an ASCX, but unlike SimpleTemplate adds controls directly to the specified container so that it will work with ASP.NET Login Controls
/// (SimpleTemplate adds the controls to a parent control and adds the parent control to the container)
/// </summary>
public class TemplateLoader : ITemplate
{
	private string _virtualPath;
	private Page _page;

	public TemplateLoader(string virtualPath, Page page)
	{
		_virtualPath = virtualPath;
		_page = page;
	}

	void ITemplate.InstantiateIn(Control container)
	{
		ITemplate template = _page.LoadTemplate(_virtualPath);
		Control tempContainer = new Control();
		template.InstantiateIn(tempContainer);

		while (tempContainer.Controls[0].HasControls())
		{
			container.Controls.Add(tempContainer.Controls[0].Controls[0]);
		}
	}
}

And to use:

_ctlPasswordRecovery.UserNameTemplate = new TemplateLoader("/_layouts/FBA/templates/PasswordRecoveryTemplate.ascx", Page);

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *