Got a Site.Master (Masterpage)
Got Default.aspx (Page)
And in the Default.aspx, there is a UserControl LoginUserControl.ascx placed
Now my problem:
In the LoginUserControl I check if Login is right.
If yes, then I set the Property IsLoggedIn on the Default.aspx to true:
//Inside LoginUserControl.ascx
if (/*Login is Ok*/)
{
((Default)Page).IsLoggedIn = true;
}
So, now I need this Information in my Masterpage Site.Master
I must know if User is logged in or not.. I do this:
//Inside Site.Master
protected void Page_Load(object sender, EventArgs e)
{
if (((Default)Page).IsLoggedIn)
{
//Do Something
}
}
But its ALWAYS false! Why? I thought I set the IsLoggedIn = true ?! Why is it then false? Is it a Lifecycle problem and what I must do, that it works :(
You should add the property IsLogged on to the viewstate of the page.
public bool IsLoggedOn {
get { return ViewState["IsLoggedOn"]==null?false:Convert.ToBoolean(ViewState["IsLoggedOn"]); }
set { ViewState["IsLoggedOn"] = value; }
}
Or if the property is used over multiple pages you should add it to the Session (replace ViewState with Session)
This is more that likely a page lifecycle issue. Page_Load in the Site.Master runs before Page_Load in your user control. What you will need to do is find the appropriate page and control events in which to apply your code.
This page has a complete breakdown of page/control/user control event life cycles and should help (scroll down to the merged events).
I think your best options are to either set IsLoggedIn property during the user controls Page_Init event or retrieve and act on it during the master page's Page_PreRender event.
Related
I am dynamically loading a user control on the page which works fine. However i am facing one problem:
I have a class level variable on the User Control code-behind and the value to the same is assigned in User Control Page Load. Now when i click the button on my aspx page which contains the user control in it and try to call the User Control function from it, i see the value of the variable which i had set in the user control-page load has been reset.
The same code works perfectly if i have the user control at design time.
Code is something like this:
Page:
MyUserControl cntrl = Page.LoadControl("~/MyUserControl.ascx")
btn_click(){
{
cntrl.TestFunction();
}
User Control:
class MyUserControl: UserControl
{
//Variable
string org="";
Page_Load()
{
org="test";
}
TestFunction()
{
//The value of org variable is empty here.
//It should however be "test" which i have set in page_load
}
}
"Code is something like this:" - when providing code (even as fragments), try to make it to comply with the language syntax - in this case C#.
In order for MyUserControl.Page_Load to fire, you have to add the user control to the control tree of the page:
MyUserControl cntrl = (MyUserControl)Page.LoadControl("~/MyUserControl.ascx");
Panel1.Controls.Add(cntrl);
The Page_Load method must have very specific signature and scope:
class MyUserControl: UserControl
{
string org="";
protected void Page_Load(object sender, EventArgs e)
{
org="test";
}
}
I'm aware this question has been asked many times before but I suspect I have a unique scenario.
I'm loading a Child Control (ASCX) and setting a Property on that Control. This works perfectly fine until postback where the property is null.
Herewith the First Class which loads the ChildControl :
protected override void CreateChildControls()
{
MyUserControl control = (MyUserControl)Page.LoadControl(_ascxPath);
control.MyProperty = base.MyProperty
Controls.Add(control);
}
Then, on my Child Control I've got the following code:
public partial class MyUserControl : UserControl
{
public MyType MyProperty { get; set; }
protected void Page_Load(object sender, EventArgs e)
{
//Exception on next line because Property is null (only on postback)
var somevalue = MyProperty.SubProperty;
Ok. Let me try to explain it.
1. Once page is created, you get full page lifecycle
2. You click on some control to create user control, and you get it
3. Now you are entering value to this control, and getting postback
4. On server side postback is handled, but as you can see viewstate actions appear as soon as page is loaded.
One of main purposes of viewstate is handling control events, to see if they are changed, or save their states or something else.
5. If on the moment, when viewstate is loaded you control is still not constructed, then all it's events and values would be ignored.
Solution either make it static control and just hide it, either create it before viewstate actions started.
You need to add the control and set properties in the Page_Init event, other wise you will lose the properties value.
In Microsoft explanations about ASP.NET page life cycle, it is written that dynamically created controls must be created in PreInit.
It worked for me.
Here is my main page :
protected global::System.Web.UI.HtmlControls.HtmlGenericControl FiltersZone;
(. . .)
protected override void OnPreInit(EventArgs e)
{
base.OnPreInit(e);
FiltersZone.Controls.Add(new PlanningFiltersSurgeonWeb());
}
This dynamically created ".ascx" control contains an hidden field :
<input id="hidTxtPaint" type="hidden" name="hidTxtPaint" runat="server" />
I am now able to retrieve its value from within dynamically created ASCX control Page_Load event, after a "submit" or a "__dopostback('hidTxtPaint')" initiated from JavaScript.
On the other hand, the hidden field's value is always empty after a POST if its parent ".ascx" control is added in main page's Page_Load event.
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");
}
I have problem passing a variable from a main page containing a user control to the user control itself. Although the passed variable is available generally in the code-behind of the user control the page_load event can't seem to read it.
My code -
In the main page code-behind:
protected void FindCCFsButton_Click(object sender, EventArgs e)
{
if (CustomerDropDown.SelectedIndex != 0)
{ SearchUcCCFList.SetCustID(CustomerDropDown.SelectedValue); }
}
(SearchUcCCFList is the instance of the user control in the main aspx page).
In the user control code behind:
public partial class ucCCFList : System.Web.UI.UserControl
{
public string srchCust { get; set; }
public void SetCustID(string custID)
{
srchCust = custID;
testCustLabel.Text = GetCustID(); //this works
}
public string GetCustID()
{
return srchCust;
}
protected void Page_Load(object sender, EventArgs e)
{
CCFGridView.DataSource = DAL.SearchCCFs(custID : GetCustID()); //doesn't work
CCFGridView.DataBind();
test2CustLabel.Text = GetCustID(); //doesn't work
}
In the Page_Load event GetCustId() doesn't return anything (so the records aren't filtered and all get returned) although it can be read in the methods outside the Page_Load.
I'm probably making a beginners error but any help would be appreciated.
Edit - following Alan's suggestion in the comments I stepped through the page loading sequence & it appears that the user control's Page_Load event is running BEFORE the code in the main page's button click so the variable is not yet available. The sequence after clicking the button is:
User control Page_Load runs
Code in button event on main page
Other code (outside Page_Load) in user control runs hence variable is available here.
This seems a bit weird, is there another way to pass the variable into the user controls Page_Load?
In this case, your click handling even on the main page is called after the user control page load call. Your variable is being set, but not until after your data binding in the user control.
Either switch the user control to declarative binding which will handle calling methods in the correct order for you. Or the easier fix in this case is to change the user control data binding from Page_Load to Page_PreRender, which is called later in the life cycle, after the main page click handling call.
protected void Page_PreRender(object sender, EventArgs e)
{
CCFGridView.DataSource = DAL.SearchCCFs(custID : GetCustID()); // will work now
CCFGridView.DataBind();
test2CustLabel.Text = GetCustID(); // will work now
}
For a more thorough answer, read up on the ASP.NET page life cycle including the interaction with user controls' life cycle.
I have a web user control (ascx) that exposes an "ID" property. What I want to do is set this property when the SelectedIndexChanged event fires in a gridview in the containing page. However, I can't seem to do it.... Here's my code:
protected void grdPhysicians_SelectedIndexChanged(object sender, EventArgs e)
{
physicians_certif1.mdID = grdPhysicians.SelectedDataKey.ToString();
mvData.SetActiveView(viewEdit);
panAdditional.Visible = true;
}
Physicians_certif1 is the user control. It seems the user control is loading before the SelectedIndexChanged event has a chance to set it's property.
Any ideas folks?
ASP.Net page lifecycles can be hard to understand especially with ascx user controls which also have their own lifecycle. If you are setting the mdID property in Page_Load of either the page or the ASCX control or have hardcoded a default value into it in the XHTML, it is probably being reset after SelectedIndexChanged fires.
Set a breakpoint in grdPhysicians_SelectedIndexChanged, set a watch on physicians_certif1.mdID and step through the code using the debugger.
Yes, that is exactly what is happening. You should look at (and be familiar with) the following resource:
ASP.Net Page Life Cycle
The page will load, then the control will load, then your events will begin to fire. If you have configuration needs based on event triggers, it is best either to place those configurations in the Page_LoadComplete or Page_PreRender events of the user control in question or apply "Rebinding" instructions in the Set method of your property:
public MyValue MyProperty()
{
get
{
return _myProperty;
}
set
{
RebindMyControls();
_myProperty = value;
}
}