With AutoEventWireUp set to false, I would normally set a Page_Finalize like this:
Include(Self.LoadComplete, Self.Page_Finalize); //Delphi
LoadComplete however, doesn't seem to be available on a MasterPage and my Page_Finalize obviously doesn't get called.
What am I meant to do to free objects in the master page?
Thanks.
LoadComplete method is simply not a member of MasterPage, but of Page.
There are several reasons for this, including the fact that the orchestrator of page life cycle is Page class itself.
It has three event-related methods: PreLoad, Load, LoadComplete. During Load, the Load event of children controls is triggered.
While a master page contains (by means of layout) the contents of the page, the page contains the MasterPage by means of objects, since the Page is the IHttpHandler that responds to HTTP requests in ASP.NET.
Briefly, you cannot override (I don't know Delphi, is that some kind of override?) OnLoadComplete in MasterPage as it's not defined. Only OnLoad
A bit late, but adding a method to the Page.LoadComplete event from the master page seems to work.
Within the master page:
protected void Page_Load(object sender, EventArgs e) {
Page.LoadComplete += Page_LoadComplete;
}
protected void Page_LoadComplete(object sender, EventArgs e) {
// do stuff on LoadComplete in the master page
}
Related
I have two .aspx pages. In the first page I have a button, on its click event the user is redirected to a second page. In the page_load event of the second page, I wrote code to download a file.
It works. But I need to download this file when the second page is completely loaded in the browser (meaning, I'm able to see all the content of the second page).
Here is my code:
Page-1
protected void ibtnReset_Click(object sender, ImageClickEventArgs e)
{
Response.Redirect("Page-2.aspx");
}
page-2
protected void Page_Load(object sender, EventArgs e)
{
// code to download file
}
The LoadComplete event of page occurs after all postback data and view-state data is loaded into the page and after the OnLoad method has been called for all controls on the page.
Example usage (in your C# code)
protected void Page_Load(object sender, EventArgs e)
{
Page.LoadComplete +=new EventHandler(Page_LoadComplete);
}
void Page_LoadComplete(object sender, EventArgs e)
{
// call your download function
}
Alternately you can use following jQuery function
$(document).ready(function()
{
//page is fully loaded and ready, do stuff here
}
it will be called only when page is loaded fully. Including all js, images and other resources.
Two ways to achieve this:
ASP.NET way -- write the file download code on "Unload" page life cycle. Unload is fired after the page has fully been rendered into the browser. Page_Load fires when the page has just started loading.
jQuery way -- inside $document.ready(){} write a call to asp.net method to download the file. $document.ready() gets executed after the your document has loaded or the document is ready. make sure u write the jquery method below the page.
Why Master pages is not required to confirm the initialization completion ?
Although, Master Page can have controls and need initialization and like in content page, confirmation comes in Init-Complete event.
InitComplete is not fired when the child controls of a control finish initialization, but when all the controls on the page are done.
The MasterPage being a control itself, loaded in the page, cannot detect by itself when all the other controls have completed initialization.
If any control, including the master page needs to know when the page initialization is over, it could subscribe to the InitComplete event of the Page.
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
Page.InitComplete += Page_InitComplete;
}
void Page_InitComplete(object sender, EventArgs e)
{
//initialization complete
//take necessary action
}
I'm a bit puzzled by the behavior of the default ASP.NET Authentication controls, by its lifecycle to be precise.
In my MasterPage, I added a LoginView Control which displays the nice [Login] or [Logout] links. When I am logged in and click on [logout], I set up the control to perform a redirection to the homepage of the application.
Internally, when a click on "logout" happens, a postback is triggered. The following steps happen (among others of course):
The page that fired the postback is reinitialized
The page that fired the postback is reloaded
The LoggingOut event is fired
The LoggedOut event is fired
The page that fired the postback is PreRendered
The redirection happens
The target page is loaded (LoggedOut.aspx in my case)
On most of the pages, this works fine. But some pages expect some data to be initialized for their rendering to happens correctly. When this loggout postback occurs, the data isn't correctly initialized, but the page is still PreRendered which leads to some... "unexpected behavior" >_<
My question is thus twofold:
Why does this rendering step happens since the page won't be displayed at all?
Is there a way to prevent the rendering to happen?
Thanks a lot.
Tim
PS: here's a small VS2010 sample project showing you the call sequence & page lifecycle if you want to try it out for yourself http://dl.dropbox.com/u/11764136/LoginTest.7z
There is a way to prevent the actual rendering of the page.
Stop processing the current request when you redirect the page. This can be done by giving a true parameter to the Response.Redirect method:
Response.Redirect("http://somewhere", true);
You can also do this manually by calling Response.Close();
Are you using if(!isPostBack) test to control what should be rendered/re-initialized and what shouldn't?
Venemo's answer gave me an idea that seems to be working.
Instead of relying on the LoginStatus component to perform the redirection, I registered the MasterPage hosting the LoginStatus components to the LoginStatus.LoggedOut event and fire the redirection "per hand" before the PreRender step can be called.
protected void Page_Load(object sender, EventArgs e)
{
MasterLoginStatus.LoggedOut += new EventHandler(OnUserLoggedOut);
}
private void OnUserLoggedOut(object sender, EventArgs e)
{
Response.Redirect("~/LoggedOut.aspx", true);
}
I was concerned the LoginStatus component might remain dirty by doing this but sofar I haven't found any issue with it e.g. "works until proven otherwise".
Remains the question of "why the component behaves like this" but I guess it was a design decision that will remain unanswered.
Edit: this works fine until you get the same problem for the "login" action. Haven't found a way around this one yet.
I've got a serious problem with a DevExpress control (The report DocumentMap) which sometimes requests the whole report, bypassing the caching mechanism, when the end-user clicks on the logout link on the LoginStatus control. I've tried a lot of approaches to stop dead the "logout" postback so that the report won't get generated (some reports took 5 minutes to render, so the logout action sometimes took that long). I think this is similar to your problem: you don't want to do any heavy processing if the user is logging out. So I've tried a different approach: why didn't I recognize that the postback is indeed a logging out postback? All my pages inherit from a base page, so I've set this code in the base page:
public bool IsLoggingOut { get; private set; }
protected override void OnPreInit(EventArgs e)
{
base.OnPreInit(e);
var eventTarget = Request.Params.Get("__EVENTTARGET");
IsLoggingOut = eventTarget != null && eventTarget.Contains("HeadLoginView$HeadLoginStatus");
}
Now all I need to do in my page is to surround any heavy processing with a test of !IsLoggingOut... You could even do you redirect to the LoggedOut page without having to handle any events, just like this:
protected override void OnLoad(EventArgs e)
{
if (IsLoggingOut)
Response.Redirect("~/LoggedOut.aspx", true);
}
Even if you prefer to use the event handler to do that redirect, being able to know that the postback is indeed due to a logout click is a nice thing!
In my case, I was having this problem with the LoginStatus control. I can't see why it is a useful design to post back and Render the page when the user has clicked "logout". Through some tests, I found that I had to let the page go through its entire lifecycle, so Reponse.End() and Response.Transfer() did not work.
My solution was to add event handlers for the LoginStatus LoggedOut event, and then override the Render() method in the master page to do nothing if the user has logged out. I actually had the LoginStatus nested inside a user control that was then in the master page, so I had to bubble the event.
In my user control containing the LoginStatus control, I added an event handler for the LoggedOut event. In the UserStatus.aspx file:
<asp:LoginStatus runat="server" ID="loginStatusDefault" OnLoggedOut="loginStatusDefault_LoggedOut" ... />
Then in the code-behind:
public event EventHandler LoggedOut;
protected void loginStatusDefault_LoggedOut(object sender, EventArgs e)
{
if (this.LoggedOut != null)
this.LoggedOut(sender, e);
}
Now in the master page default.master, I have already included the UserStatus control:
<c:userstatus ID="ctlUserStatus" runat="server" />
and in the code-behind:
protected void Page_Init(object sender, EventArgs e)
{
ctlUserStatus.LoggedOut += ctlUserStatus_LoggedOut;
...
}
bool IsLoggedOut { get; set; }
void ctlUserStatus_LoggedOut(object sender, EventArgs e)
{
IsLoggedOut = true;
}
protected override void Render(HtmlTextWriter writer)
{
if (!IsLoggedOut)
base.Render(writer);
}
For me, the page rendering is what was bombing out when the user clicked "logout", so this took care of the problem for all pages.
What I did was have the logout link or onloggingout control just redirect to another page, "Logout.aspx" which then handles the log out code. Works great actually.
protected void LoginStatus1_LoggingOut(object sender, EventArgs e)
{
Response.Redirect("~/Logout.aspx");
}
In the MSDN page lifecycle reference it states that the pre-init is used to "Create or re-create dynamic controls."
However, elsewhere on MSDN, an example implies that a dynamic user control should be loaded in Page_Load
Is this a contradiction? Or is pre-init used only for standard aspx controls?
What have I missed :)
Edit:
Either way works, however, there is presumably some benefit of one approach over the other.
(WebUserControl1 is a UserControl with a simple label property, SomeProperty)
protected override void OnPreInit(EventArgs e)
{
base.OnPreInit(e);
WebUserControl1 wc1 = LoadControl(#"~\WebUserControl1.ascx") as WebUserControl1;
wc1.SomeProperty = "Hello World";
Controls.Add(wc1);
}
protected void Page_Load(object sender, EventArgs e)
{
WebUserControl1 wc1 = LoadControl(#"~\WebUserControl1.ascx") as WebUserControl1;
wc1.SomeProperty = "Hello World";
Controls.Add(wc1);
}
What exactly are you trying to do? Are you trying to pass information to the user control? If so you can pass the information to the user control in the page_load event from the parent page.
The answer is it depends on your custom control. If your user control doesn't need anything to happen before page_load, then you can go ahead and add your control during page load, if you have code in your user control that executes at an earlier time, then you should add your control at an earlier stage as the MSDN article suggests.
I am trying to change the master page dynamically, and although it's easy to do from a content page (overriding OnPreInit), there is no such event for a master page. Is it possible to introduce this event somehow?
UPDATE: I got halfway there by going via the PreInit of the pages at the bottom of the ladder, turns out you can do things like base.Master.MasterPageFile = "/master.Master";, but for some reason this doesn't load the stuff in the header of the top-most master page, namely stylesheets.
Quoting from: Can I change a nested master page's master dynamically?
Just tested this and it works from the PreInit of the Page that is using the nested MasterPage.
protected void Page_PreInit(object sender, EventArgs e)
{
this.Master.MasterPageFile = "/Site2.Master";
}
Obviously you will need to ensure that the ContentPlaceholderIds are consistent across the pages you are swapping between.
If you overrode the MasterPageClass and added your own onPreInit you might could do it, but I don't think even that would work. There's definitely no construct for it according to Reflector, nothing to even override, altho since it inherits UserControl then there's always OnInit ... alternately you could attempt to override get_Master() but that might not work either ...
Use the masterpage constructor.
Let's say you want to use a different master page without a menu, pass query string NoMenu.
protected void Page_PreInit(object sender, EventArgs e)
{
//You'll go through infinite loop if you do not check if we already have the new master page, this will switch to different master page if requested without a menu for example
if (Request.QueryString["NoMenu"] != null && this.MasterPageFile != "/MasterPageNoMenu.master")
{
this.MasterPageFile = "/MasterPageNoMenu.master";
base.OnPreInit(e);
}
}