LoadPostData not being called at the right time for controls dynamically added at page load

S

Sam

I have a custom control (MyTextBox - taken from Microsoft website)
that implements the IPostBackDataHandler interface. It is added to
the controls collection of a placeholder control during the Page Load
of a main ASPX page. Now if we debug the MyTextBox, we find the order
of events like so (during a Posback, of course): OnInit -> OnLoad ->
LoadPostData.

My question is why does the LoadPostData occur *after* the OnLoad
instead of before?

Now I know about the conventional wisdom that says this is a "Begin
ProcessPostData Second Try" issue. That controls added during page
load will have LoadPostData called *after* their page loads and not
before. But my question is the following. Given that:

1) The newly added control (MyTextBox) plays catch up when added to
the controls collection on Page Load of the main form, and

2) When the newly added control's Init method is called (while playing
catchup) it has a UniqueID that matches the name key in the Forms
collection and a value with the correct submitted textbox data (I've
verified this by inserting breakpoints in MyTextBox),

Thefore:

Why isn't LoadPostData called between the Init and Load events when
the control is added to the control tree? All the preconditions are
there - MyTextBox implements IPostBackDataHandler and has a UniqueID
that matches the Form's name collection. This is true at least during
the Init event of MyTextBox. So it seems to me that the next event to
be fired for MyTextBox would be LoadPostData. But that doesn't happen
(at least not until *after* PageLoad).

BTW, Assigning an ID to MyTextBox on the Init method of the main page
gives the exact same results (except of course the MyTextBox ID is
different).

It sure would make it a lot easier on me if it fired the LoadPostEvent
when it usually does. Calling it *after* the PageLoad of the main
page seems a bit hackish on Microsoft's part. Can anyone shed some
more light on why the internals work the way they do? And is there an
easy way to fix it in my code below?

Thanks for considering.

-Sam




Code follows:

-------
<%@ Page language="c#" Codebehind="Test.aspx.cs"
AutoEventWireup="false" Inherits="Test" %>
<html>
<body>
<form id="Form1" method="post" runat="server">
<asp:placeHolder id=holder runat=server></asp:placeHolder>
</form>
</body>
</html>

------

using System;
using System.Web.UI.WebControls;

public class Test : System.Web.UI.Page
{
private MyTextBox txtBox = new MyTextBox();
private Button btnPress = new Button();
protected PlaceHolder holder;

override protected void OnInit(EventArgs e)
{
InitializeComponent();
base.OnInit(e);
}

protected override void OnLoad(EventArgs e)
{
this.holder.Controls.Add(txtBox);
base.OnLoad (e);
}

private void InitializeComponent()
{
holder.Controls.Add(btnPress);
btnPress.Text = "Do Postback";

}
}
-------

using System;
using System.Web;
using System.Web.UI;
using System.Collections.Specialized;

public class MyTextBox: Control, IPostBackDataHandler
{
private String text = String.Empty;

public String Text
{
get
{
return text;
}
set
{
text = value;
}
}

public event EventHandler TextChanged;

protected override void OnLoad(EventArgs e)
{
base.OnLoad (e);
}

protected override void OnInit(EventArgs e)
{
base.OnInit (e);
Page.RegisterRequiresPostBack(this);
}

public virtual bool LoadPostData(string postDataKey,
NameValueCollection values)
{
String presentValue = Text;
String postedValue = values[postDataKey];
if (!presentValue.Equals(postedValue))
{
Text = postedValue;
return true;
}
return false;
}

public virtual void RaisePostDataChangedEvent()
{
OnTextChanged(EventArgs.Empty);
}

protected virtual void OnTextChanged(EventArgs e)
{
if (TextChanged != null)
TextChanged(this,e);
}

protected override void Render(HtmlTextWriter output)
{
output.AddAttribute(HtmlTextWriterAttribute.Type, "text");
output.AddAttribute(HtmlTextWriterAttribute.Value, this.Text);
output.AddAttribute(HtmlTextWriterAttribute.Name, this.UniqueID);
output.RenderBeginTag(HtmlTextWriterTag.Input);
output.RenderEndTag();
}
}
}
 
T

Teemu Keiski

Good notes,

the key is that it is the Page that initiates postback data loading,
changed events raising as well postback event raising and it does it at
fixed stages (as you noted ). Lifecycle stages like Init, Load and such are
raised in catchup scenario by the ControlCollection but it does not do
postback data loading.(in normal static control scenario page initiates the
recursive traversing of controls in these stages). Postback data loading is
Page-only property.

--
Teemu Keiski
MCP, Microsoft MVP (ASP.NET), AspInsiders member
ASP.NET Forum Moderator, AspAlliance Columnist
http://blogs.aspadvice.com/joteke

I have a custom control (MyTextBox - taken from Microsoft website)
that implements the IPostBackDataHandler interface. It is added to
the controls collection of a placeholder control during the Page Load
of a main ASPX page. Now if we debug the MyTextBox, we find the order
of events like so (during a Posback, of course): OnInit -> OnLoad ->
LoadPostData.

My question is why does the LoadPostData occur *after* the OnLoad
instead of before?

Now I know about the conventional wisdom that says this is a "Begin
ProcessPostData Second Try" issue. That controls added during page
load will have LoadPostData called *after* their page loads and not
before. But my question is the following. Given that:

1) The newly added control (MyTextBox) plays catch up when added to
the controls collection on Page Load of the main form, and

2) When the newly added control's Init method is called (while playing
catchup) it has a UniqueID that matches the name key in the Forms
collection and a value with the correct submitted textbox data (I've
verified this by inserting breakpoints in MyTextBox),

Thefore:

Why isn't LoadPostData called between the Init and Load events when
the control is added to the control tree? All the preconditions are
there - MyTextBox implements IPostBackDataHandler and has a UniqueID
that matches the Form's name collection. This is true at least during
the Init event of MyTextBox. So it seems to me that the next event to
be fired for MyTextBox would be LoadPostData. But that doesn't happen
(at least not until *after* PageLoad).

BTW, Assigning an ID to MyTextBox on the Init method of the main page
gives the exact same results (except of course the MyTextBox ID is
different).

It sure would make it a lot easier on me if it fired the LoadPostEvent
when it usually does. Calling it *after* the PageLoad of the main
page seems a bit hackish on Microsoft's part. Can anyone shed some
more light on why the internals work the way they do? And is there an
easy way to fix it in my code below?

Thanks for considering.

-Sam




Code follows:

-------
<%@ Page language="c#" Codebehind="Test.aspx.cs"
AutoEventWireup="false" Inherits="Test" %>
<html>
<body>
<form id="Form1" method="post" runat="server">
<asp:placeHolder id=holder runat=server></asp:placeHolder>
</form>
</body>
</html>

------

using System;
using System.Web.UI.WebControls;

public class Test : System.Web.UI.Page
{
private MyTextBox txtBox = new MyTextBox();
private Button btnPress = new Button();
protected PlaceHolder holder;

override protected void OnInit(EventArgs e)
{
InitializeComponent();
base.OnInit(e);
}

protected override void OnLoad(EventArgs e)
{
this.holder.Controls.Add(txtBox);
base.OnLoad (e);
}

private void InitializeComponent()
{
holder.Controls.Add(btnPress);
btnPress.Text = "Do Postback";

}
}
-------

using System;
using System.Web;
using System.Web.UI;
using System.Collections.Specialized;

public class MyTextBox: Control, IPostBackDataHandler
{
private String text = String.Empty;

public String Text
{
get
{
return text;
}
set
{
text = value;
}
}

public event EventHandler TextChanged;

protected override void OnLoad(EventArgs e)
{
base.OnLoad (e);
}

protected override void OnInit(EventArgs e)
{
base.OnInit (e);
Page.RegisterRequiresPostBack(this);
}

public virtual bool LoadPostData(string postDataKey,
NameValueCollection values)
{
String presentValue = Text;
String postedValue = values[postDataKey];
if (!presentValue.Equals(postedValue))
{
Text = postedValue;
return true;
}
return false;
}

public virtual void RaisePostDataChangedEvent()
{
OnTextChanged(EventArgs.Empty);
}

protected virtual void OnTextChanged(EventArgs e)
{
if (TextChanged != null)
TextChanged(this,e);
}

protected override void Render(HtmlTextWriter output)
{
output.AddAttribute(HtmlTextWriterAttribute.Type, "text");
output.AddAttribute(HtmlTextWriterAttribute.Value, this.Text);
output.AddAttribute(HtmlTextWriterAttribute.Name, this.UniqueID);
output.RenderBeginTag(HtmlTextWriterTag.Input);
output.RenderEndTag();
}
}
}
 
S

Sam

Thank you very much Teemu for the answer to this question.

I find this link:
http://aspalliance.com/articleViewer.aspx?aId=134&pId=
much better than the official Microsoft control lifecycle link. From
the table at the bottom of the above link you can see those events
marked as 'All' in the Controls column may participate in the 'catch
up' phase.

This is only one example where Microsoft's documentation appears to be
incomplete. For some reason this knowledge is being spread on these
newsgroups rather than being available at Microsoft's site - almost
like the 'tribal knowledge' of yore.

-Sam
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top