AspAlliance.com LogoASPAlliance: Articles, reviews, and samples for .NET Developers
URL:
http://aspalliance.com/articleViewer.aspx?aId=399&pId=-1
Differences in ASP.NET’s LoadControl vs. LoadTemplate
page
by Denis Bauer
Feedback
Average Rating: This article has not yet been rated.
Views (Total / Last 10 Days): 12946/ 14

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.


Product Spotlight
Product Spotlight 

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