The page lifecycle for controls(order constructed from a page) - c#

For example, lets say I have a page and 2 custom controls on that page. During what event on page do these controls get constructed. When does their page_init get called?
Also, for these 2 custom controls, do they both get constructed before either of the page_init events get called?
I've done some testing with a debugger and such, but I'm wanting a definite answer to these questions. I'm not wanting to make code that works only sometimes.

The official page in the documentation describes the page lifecycle in details, but a picture is worth a thousand words :
If I understand correctly, controls are constructed between the PreInit and Init of the page. Thus, controls' Init methods are called before the page's Init method.
According to the schema, Construct and FrameworkInitialize are called on each control before the Init event are fired, which means that all controls should be constructed and available when entering a specific control's Init method.

Related

When exactly do Page.RegisterAsyncTask's get called?

I am running into confusing behavior related to async code registered on an ASP.NET page with RegisterAsyncTask, ViewState, and checkboxes, and I need to know exactly when these async-tasks run relative to when ViewState is saved.
I have a few checkboxes inside an ASP:PlaceHolder control. I am reading a record and populating the checkboxes, then I make the PlaceHolder visible.
If all this is synchronous - maybe within Page_Load - all is well.
If this is registered as an async task the following happens:
The checkboxes get populated.
The Placeholder is visible.
On postback, checkboxes cannot be UNCHECKED. That is, if they were initially checked they retain their checked status even if the user unchecked them. It seems like the checkboxes revert back to their initial values. If a checkbox is checked on the client, that makes it! Unchecking doesn't.
This doesn't seem to be a problem with textboxes. I haven't tried other widgets.
I can 'correct' this problem by setting the PlaceHolder to be visible BEFORE I register the async task. I think this is similar to my other question about Grid visiblity:
asp:DataGrid visibility with async?
It's turning out to be very difficult and resulting in confusing code as I try to pull all the visiblity-rules out of async methods.
I see from the ASP.NET page lifecycle that gets saved sometime before OnPreRender. I also think RegisterAsyncTask'd code gets run about the same time. What order does this happen in? If ViewState is saved before my code runs I'm sunk!
Edit: I found some more detail but it is still confusing:
Halfway down this page: http://www.asp.net/web-forms/overview/performance-and-caching/using-asynchronous-methods-in-aspnet-45 it says
"Methods hooked up with RegisterAsyncTask will run immediately after PreRender."
This page: https://msdn.microsoft.com/en-us/library/ms178472(v=vs.85).aspx details the PreRender and SaveStateComplete events but doesn't mention RegisterAsyncTask. I need to experiment to see if its shoe-horned between them.
The ExecuteRegisteredAsyncTasks gives you some more control in when the tasks are being started.
The ExecuteRegisteredAsyncTasks method is automatically called at the
point in the page processing when any registered asynchronous tasks,
if they exist, are invoked for a non-asynchronous page. This automatic
call to ExecuteRegisteredAsyncTasks occurs just before the
PreRenderComplete event.
From PreRenderComplete documentation:
This is the last event raised before the page's view state is saved.

Winform app, force execute OnLoad Event when focus is on another tab

I have a WinForm app, the form has TabControl, control has three tabs tabPage1,tabPage2,tabPage3.
The Tab 'tabPage3' is hosting a User defined control which internally has one or more child controls.
Now my problem lies in tabPage3,
I know it is a pure Winforms behavior, until your parent is not activated child controls Onload event won't fire.
I have a requirement to force the Onload event to fire when the focus is on tabPage1, tabPage2. Is there any way to force the Onload event to fire.
I have already visited following links but didn't find any clue. Link Link Link
This is a very unusual requirement, strongly smells like an XY problem. The Load event is heavily over-used in Winforms, a side-effect of it being the default event for a Form or UserControl. One of the behaviors inherited from VB6, the Load event was a big deal in that language. What you want can easily be accomplished by not giving Winforms a choice:
public UserControl3() {
InitializeComponent();
CreateHandle();
}
The CreateHandle() call does the forcing, OnLoad will immediately run. But do be aware that this happens very early, too early to do the kind of things that you'd really want to use OnLoad() or the Load event for. Which are rather limited, it is only truly necessary to discover the actual Location and Size of the control. Anything else belongs in the constructor. Surely including the code that you now run in OnLoad().
Strongly favor using the constructor instead.
I had a similar problem for a previous project, for my needs I managed to just iterate over every tab page in the forms constructor (or possibly OnLoad I can't remember) and then reset the index back to 0 before ever showing the end user.
Something similar to:
for(int i = 1; i < tabControl.TabCount; i++)
tabControl.SelectTab(i);
tabControl.SelectTab(0);

sharepoint webpart with many usercontrols

I have created sharepoint 2010 visual webpart in VisualStudio2010 with three user controls (.ascx). I want to dynamically change usercontrol in the webpart by clicking some button at currently loaded usercontrol. The main problem consist in the fact that buttonClick event is handled only after execution CreateChildControls method (where I try to get needed usercontrol using ViewData). Could anyone please help me to solve this problem?
Lee's response is basically right and may work well for you. However, you should not just use __doPostBack and rely that it will be always "magically" there for you. This method and variables mentioned by Lee are internal to ASP.NET and they are not meant to be used directly. Also, if you do not place any postback-ing control on your page this method will actually not be generated and your code calling it would fail.
Luckily, the code to cause and handle a generic postback is very simple. Instead of using built-in event handlers of input controls (which need to be constructed before being triggered - hence the call to CreateChildControls before your handler is called) you would target the postback to the Web Part itself:
public class MyWebPart : WebPart, IPostBackEventHandler {
protected override void CreateChildControls() {
Control clickable = ...; // Create a clickable control.
// Get JavaScript expression to send postback "test" to "this" web part.
var postBack = Page.ClientScript.GetPostBackEventReference(this, "test");
clickable.Attributes["onclick"] = postBack + "; return false";
Controls.Add(clickable);
}
void IPostBackEventHandler.RaisePostBackEvent(string eventArgument) {
if (eventArgument == "test") { // Recognize and handle our postback.
...
}
}
}
The GetPostBackEventReference will generate the necessary JavaScript expression for you. (And actually, just calling it makes the __doPostBack "magically" appear on the page.) The RaisePostBackEvent will be called between OnLoad and OnPreRender. Make sure not to cause child controls be created before that (by calling EnsureChildControls, for example, or by any other means). If you need multiple postback-ing controls the eventArguments parameter will let you differ among them.
You need the postback triggers in your user controls and not directly in the Web Part. I showed it in the Web Part just to keep it simple. You can put the result of GetPostBackEventReference to any control providing you use the right Page and Web Part instances when calling it.
--- Ferda
A way to do this would be have the button call a javascript function that in turn calls the following:
__doPostBack('LoadControl', 'ControlName');
You can then use the server variables __EVENTTARGET and __EVENTARGUMENT to find out which control to load within your CreateChildControls event handler.
I had that problem too.
Add this to the event handler (after executing your code inside the handler)
this.Page.Response.Redirect(HttpContext.Current.Request.Url.AbsoluteUri, true);
Regards,
Pedro

What is the proper use of EnsureChildControls()?

Most often I use it when I am accessing a property of a composite control that depends on a child control. But I have also added it to OnInit of a control so I could make sure a hidden field was added correctly. Just a minute ago I called it in RenderControl because I was having an issue rendering a calendar extender and it fixed it. I am starting to get a little confused on when I need to and when I don't need to call EnsureChildControls and when I should call it. Any pointers are welcome. Thanks!
EnsureChildControls triggers CreateChildControl if it’s not already triggered before. This has to be done only one-time in the page life cycle. I call it unconditionally in OnInit / Page_Init and nowhere else. This place has the advantage that the controls are created before ASP.NET loads the ViewState. If you use the ViewState or ControlState it is necessary to create the child controls that early.
EnsureChildControls method makes sure child controls are created prior to accessing them.
Anytime you write composite controls for example, you want to build your controls inside the CreateChildControls events then call EnsureChildControls before accessing them to make sure all the controls have been created so you dont get a null reference exception.

Dynamically created controls and the ASP.NET page lifecycle

I'm working on an ASP.NET project in which the vast majority of the forms are generated dynamically at run time (form definitions are stored in a DB for customizability). Therefore, I have to dynamically create and add my controls to the Page every time OnLoad fires, regardless of IsPostBack. This has been working just fine and .NET takes care of managing ViewState for these controls.
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
RenderDynamicControls()
}
private void RenderDynamicControls()
{
//1. call service layer to retrieve form definition
//2. create and add controls to page container
}
I have a new requirement in which if a user clicks on a given button (this button is created at design time) the page should be re-rendered in a slightly different way. So in addition to the code that executes in OnLoad (i.e. RenderDynamicControls()), I have this code:
protected void MyButton_Click(object sender, EventArgs e)
{
RenderDynamicControlsALittleDifferently()
}
private void RenderDynamicControlsALittleDifferently()
{
//1. clear all controls from the page container added in RenderDynamicControls()
//2. call service layer to retrieve form definition
//3. create and add controls to page container
}
My question is, is this really the only way to accomplish what I'm after? It seems beyond hacky to effectively render the form twice simply to respond to a button click. I gather from my research that this is simply how the page-lifecycle works in ASP.NET: Namely, that OnLoad must fire on every Postback before child events are invoked. Still, it's worthwhile to check with the SO community before having to drink the kool-aid.
On a related note, once I get this feature completed, I'm planning on throwing an UpdatePanel on the page to perform the page updates via Ajax. Any code/advice that make that transition easier would be much appreciated.
From Dirk to Dirk :-)
What do you mean with RenderDynamicControls? Create and set controls? If this is your intention not ASP.NET is managing your ViewState, but you do. If you fill the controls on every load, you always overwrite the existing ViewState!
If you want to use the ViewState, create your controls in the pages init event and fill them in the load event, but only if the request isn’t a postback. This is necessary, because ASP.NET recreates the ViewState between init and load. And this is also the reason for the two “rendering cycles” you describe. You need the first control creation cycle because ASP.NET can’t restore the ViewState without a proper control set and ASP.NET can’t react proper on your response without it.
Back to your code: In general your RenderDynamicControlsALittleDifferently wouldn’t work - because you create your controls too late in the pages life cycle and you would damage the ViewState by inserting new objects to the control collection. In a similar situation I solved this problem by a redirecting the page to itself (Response.Redirect). In this case RenderDynamicControls would do the job, based on a “little differently situation” after you change your internal state.

Categories

Resources