Hi,
I'm trying to use a simple user control to create a template for my site. I then want to use this control to nest my page's content within it. I can nest all controls I've tried so far and it works well. However, as soon as I add an event handler to any of those nested controls, the page loads a NullReference error message.
I suspect that event handler binding takes place before the user control that contains the nested control loads, and therefore before the nested controls are instantiated, leaving the nested controls null at handler binding time (when InitializeComponent is called)
I'd like to modify my user control to avoid this kind of problem if possible... anyone have any ideas on how this might be done?
Here's the code I have for the user control (template.ascx) so far.
Code:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" >
<HTML xmlns:fo="http://www.w3.org/1999/XSL/Format">
<HEAD>
<title>
<%=this.Title%>
</title>
<script runat="server">
/// <summary>
/// Insert the body the user provided in our body placeholder.
/// </summary>
protected override void CreateChildControls()
{
// insert the main content body if available
if( null != Body )
Body.InstantiateIn( bodycontainer );
}
</script>
</HEAD>
<body>
<div>Header</div>
<div><asp:placeholder id="bodycontainer" runat="server" /></div>
<div>Footer</div>
</body>
</HTML>
And it's code behind
Code:
namespace Testing
{
using System;
using System.Data;
using System.Drawing;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
/// <summary>
/// Summary description for template.
/// </summary>
[ParseChildren(true)]
public class template : UserControl, INamingContainer
{
protected System.Web.UI.WebControls.PlaceHolder bodycontainer;
/// <summary>
/// The main content template.
/// </summary>
private ITemplate main;
/// <summary>
/// The name of the page.
/// </summary>
private string title;
/// <summary>
/// The main content template.
/// </summary>
public ITemplate Body
{
get { return this.main; }
set { this.main = value; }
}
/// <summary>
/// The name of the page.
/// </summary>
public string Title
{
get { return this.title; }
set { this.title = value; }
}
private void Page_Load(object sender, System.EventArgs e)
{
// Put user code to initialize the page here
}
protected override void CreateChildControls()
{
// insert the main content body if available
if( null != Body )
{
Trace.Warn("Instantiating Template");
Body.InstantiateIn(bodycontainer);
}
}
#region Web Form Designer generated code
override protected void OnInit(EventArgs e)
{
//
// CODEGEN: This call is required by the ASP.NET Web Form Designer.
//
InitializeComponent();
base.OnInit(e);
}
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.Load += new System.EventHandler(this.Page_Load);
}
#endregion
}
}
Here's the page that uses the user control
Code:
<%@ Register TagPrefix="nm" TagName="template" Src="template.ascx"%>
<nm:template id="template" title="Example of Page Templating" runat="server">
<body>
<form id="tester_form" runat="server">
<asp:Label id="Label1" runat="server">Label</asp:Label>
<asp:Button id="Button2" runat="server" Text="Button" OnClick="Button2_Click"></asp:Button>
</form>
</body>
</nm:template>
And it's code behind
Code:
using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Web;
using System.Web.SessionState;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
namespace Testing
{
/// <summary>
/// Summary description for test.
/// </summary>
public class test : System.Web.UI.Page
{
protected System.Web.UI.WebControls.Button Button2;
protected System.Web.UI.WebControls.Label Label1;
private void Page_Load(object sender, System.EventArgs e)
{
// Put user code to initialize the page here
}
#region Web Form Designer generated code
override protected void OnInit(EventArgs e)
{
//
// CODEGEN: This call is required by the ASP.NET Web Form Designer.
//
InitializeComponent();
base.OnInit(e);
}
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
Trace.Warn("this.Button2 " + (this.Button2 == null ? "=" : "!") + "= null"); //Returns null
Trace.Warn("Button2 " + (Button2 == null ? "=" : "!") + "= null"); //Returns null
//this.Button2.Click += new System.EventHandler(this.Button2_Click); //Throws a NullException
this.Load += new System.EventHandler(this.Page_Load);
}
#endregion
public void Button2_Click(object sender, System.EventArgs e)
{
this.Label1.Text = "Clicked!";
Trace.Warn("Clicked");
}
}
}