Differences in ASP.NET’s LoadControl vs. LoadTemplate
page 1 of 1
Published: 25 Mar 2004
Unedited - Community Contributed
Abstract
This article explains some subtle differences between loading UserControls with Page.LoadControl and Page.LoadTemplate
by Denis Bauer
Feedback
Average Rating: This article has not yet been rated.
Views (Total / Last 10 Days): 12944/ 18

Differences in ASP.NET’s LoadControl vs. LoadTemplate

1 Introduction

While developing the HierarGrid I noticed that there are some subtle differences between loading UserControls with Page.LoadControl and Page.LoadTemplate. Without digging deeper into that I decided to add a property “TemplateControlMode” to the HierarGrid so that the developer can choose which way to load the template.

After some users asked what the "right" setting for the property is or reported exceptions that were related to choosing the "wrong" setting, I decided to take a look at the two implementations to find the differences. This article explains what I've found.

2 Analyzing the two methods

At first sight both methods LoadControl and LoadTemplate look similar. They call into UserControlParser.GetCompiledUserControlType which picks up the ASCX file, compiles it into an assembly and returns a new type (ASP_[UserControlName]_ascx). Here comes the first difference: While LoadTemplate wraps the new Type object in a class called SimpleTemplate (which implements ITemplate and therefore has the well-known method InstantiateIn), LoadControl does some further processing in LoadControl(Type).

To explain that in more detail, consider the following code. When using the LoadTemplate method the typical user code looks like this:

ITemplate template = Page.LoadTemplate("xyz.ascx");
template.InstantiateIn(parentControl);

Behind the scenes that does (simplified):

ITemplate template = Page.LoadTemplate("xyz.ascx");
{
 type = UserControlParser.GetCompiledUserControlType("xyz.ascx",...);
 template = new SimpleTemplate(type);
 return template;
}
template.InstantiateIn(parentControl);
{
 control = HttpRuntime.CreateNonPublicInstance(type);
 control.SetNonBindingContainer();
 parentControl.Controls.Add(control);
}

If we compare that to the typical LoadControl code:

control = Page.LoadControl("xyz.ascx");
container.Controls.Add(control);

Behind the scenes this relates to (again simplified):

control = Page.LoadControl("xyz.ascx");
{
 type = UserControlParser.GetCompiledUserControlType("xyz.ascx",...);
 control = HttpRuntime.CreateNonPublicInstance(type);
 control.InitializeAsUserControl(base.Page);
 return control;
}
container.Controls.Add(control);

So the main differences are the two lines InitializeAsUserControl when using LoadControl and SetNonBindingContainer when using LoadTemplate.

3 Difference One: child control creation

Let's take a closer look at the first. The method UserControl.InitializeAsUserControlInternal() does two things: Call HookUpAutomaticHandlers (didn't take a look at it - most likely used for AutoEventWireUp) and FrameworkInitialize. The latter should be familiar to anyone who has ever taken a look at the code that is automatically generated by the framework for ASPX and ASCX files. It is responsible for building the controls hierarchy.

So does this mean that InitializeAsUserControl is not called for a UserControl created with LoadTemplate? And how is the child control hierarchy populated then?

Basically, it is called - just not as early. I noticed that the implementation of OnInit in the UserControls class invokes InitializeAsUserControl if it has not already been called.

What does this mean in practice? Imagine a UserControl that contains the following code:

override protected void OnInit(EventArgs e)
{
 InitializeComponent();
 base.OnInit(e); //calls InitializeAsUserControl which
//invokes FrameworkInitialize
}

private void InitializeComponent()
{
 this.Load += new System.EventHandler(this.Page_Load);
 this.MyControl.DataBinding += new System.EventHandler(this.MyControl_DataBinding);
}

If instantiated with LoadControl, FrameworkInitialize is called immediately by InitializeAsUserControl and the Controls collection is populated. When adding the UserControl to the parent container the OnInit event is invoked and the delegate is successfully attached. No problem so far!

Control c = Page.LoadControl("x.ascx"); //calls InitializeAsUserControl 
//which invokes FrameworkInitialize
parentContainer.Controls.Add(c); //OnInit is raised and the delegate attached.

If instantiated with LoadTemplate things looks differently:

ITemplate template = Page.LoadTemplate("xyz.ascx")
template.InstantiateIn(parentContainer);
As mentioned above, this only adds an instance of the template to the parent container causing the Init event to be raised. When OnInit is called in our UserControl it tries to add the delegates and the red line crashes with a null reference exception. 
Why that? Because the child control collection has not been populated by FrameworkInitialize and therefore MyControl is still null. If we switch the two lines in OnInit everything works fine. base.OnInit calls InitializeAsUserControl which causes the controls collection to be filled and the delegate can be attached.

4 Difference Two: BindingContainer

As I mentioned above, when loading the UserControl with LoadTemplate the method SetNonBindingContainer is invoked. This sets a flag on the control that changes the behavior of the BindingContainer property as follows:
When you use the classical databinding syntax in ASP.NET DataBinder.Eval(Container.DataItem, "Field") you may have wondered what Container actually represents. If you take a look at the code ASP.NET generates, you will notice that it is a shortcut to the BindingContainer property. This property normally returns a reference to the NamingContainer. So for example if you have a Label inside a panel that is hosted on a UserControl calling Label.BindingContainer gives a reference to the UserControl.

However if the UserControl is flagged as NonBindingContainer the call to Label.BindingContainer retrieves the UserControl's BindingContainer.

What does this mean in practice?
Imagine you have a Grid whose ItemTemplate contains a databound Label. As the ItemTemplate is internally loaded with LoadTemplate the NonBindingContainer flag is set and the template passes calls to its BindingContainer property on to its NamingContainer’s BindingContainer. So Container.DataItem would access the DataItem property of the DataGridItem (representing the current row) which contains the DataRowView of the record that is currently processed. Everything works just fine!

But, if this template is loaded with LoadControl (as you can set with the HierarGrid property "LoadTemplateMode") the UserControl is marked as a BindingContainer and the databinding expression Container.DataItem tries to access the UserControl's DataItem which is empty. To correct that, you could change the code to Container.BindingContainer.DataItem.

5 Differences in .NET Framework 1.1

After I found these differences in the .NET framework 1.0, I compared the findings with 1.1 and noticed that InitializeAsUserControl now is called in the InstantiateIn method as well. So what I explained as difference one should not occur when using the assembly with the new version.

6 Conclusion

To sum it up, there are two main differences between Page.LoadControl and Page.LoadTemplate. When using LoadControl in the .NET Framework 1.0, the child control hierarchy is populated immediately whereas when using LoadTemplate it is filled in UserControls.OnInit. The second difference relates to the BindingContainer property. When using LoadTemplate the UserControl is flagged as NonBindingContainer and calls to this property are passed on to the NamingContainer's BindingContainer.

Hopefully this summary explains the two main problems developers face when having to decide which method to use.

If you have any feedback regarding this article, I’ll be happy if you let me know either directly or through the blog comments on my homepage http://www.denisbauer.com.

About the Author

 

Denis Bauer is a Software Design Engineer at Microsoft Germany’s Consulting Services where he is working on large .NET projects. Denis specializes on web application development with ASP.NET and the .NET Framework. Before joining Microsoft in 2001, he held leading positions in two new economy startup companies.



User Comments

Title: USER CONTROL   
Name: Reiner
Date: 2008-03-20 6:15:02 PM
Comment:
Hello

first excuse my English, Spanish is my mother language

I have a problem and may be you can help me , I am working in a ASP.NET project using VS 2008

I want to create a "user control" or something similar... but I like that with one usercontrol.ascx file I like to dynamically load different usercontrol.ascx.sc file

because I have many situation...

it is that possible?


Thanks

Reiner
reinerra@gmail.com
Title: Problem   
Name: karthik
Date: 2006-11-20 12:00:30 AM
Comment:
Hai,

I have one doubt.My Task is also related to this.i load the usercontrol externally using loadcontrol method.but i cant get the instance to call the method in usercontrol.what can i do.hardcoded usercontrol.
Title: Caching   
Name: Manikandan
Date: 2005-11-30 12:03:30 AM
Comment:
Hello
is is posssible to add caching for this template. i have tryed with partial caching its not working for Templates.
Title: great insight   
Name: Michael Bui
Date: 2005-10-27 3:39:06 PM
Comment:
solved my problem with events not being wired up the control, I was using LoadControl on a custom control and loading the control into a place holder. The events where being lost during a edit command which caused createitem to be called twice during the trip to the server. Load control didnt get the control loaded into the naming collection of the naming container. I am still not sure extactly why. I read this article thinking that i can get the control immediately loaded with the naming container. Boom, it worked. events wired.
Title: @Mohsen   
Name: Denis Bauer
Date: 2005-10-17 5:53:01 AM
Comment:
Hi Mohsen,

can you elaborate a bit more on your problem? I don't quite understand the scenario you are talking about.

Thanks
Denis
Title: Loading usercontrol dll later   
Name: Mohsen
Date: 2005-10-16 10:41:54 PM
Comment:
Hello

I read your post. I have a question. If my user control have codebehind I should add a reference of its dll. How if I want to add it later with some way like loading Assembly?

Thanks in advance
Mohsen
Title: My Problem   
Name: Milind
Date: 2005-09-15 8:13:54 AM
Comment:
Hello
i like your article
but i have some differ problem
i am creating a UserControl in my ASP.NET Application
and i want to reload it in Button's Click Event
so how can i do it ?
plz help me
Thanx.

Product Spotlight
Product Spotlight 





Community Advice: ASP | SQL | XML | Regular Expressions | Windows


©Copyright 1998-2024 ASPAlliance.com  |  Page Processed at 2024-04-19 10:08:44 PM  AspAlliance Recent Articles RSS Feed
About ASPAlliance | Newsgroups | Advertise | Authors | Email Lists | Feedback | Link To Us | Privacy | Search