Apologies if this is too trivial but I seem to be running into an issue where I cannot access an object from a nested master page.
I'm having trouble passing down a User object from my main master to my nested master. By the time it gets to my nested master page it's null. I don't ever remember having trouble getting master pages talking but in this instance it just doesn't want to work.
So the set up, Some code omitted:
public partial class RWCMSMain : System.Web.UI.MasterPage
{
public Business.BusinessEntities.User LoggedOnUser { get; set; }
protected void Page_Load(object sender, EventArgs e)
{
//Get the user
var loggedOnUser = userRepo.GetUser(securityToken);
//Now set the property
this.LoggedOnUser = loggedOnUser;
}
}
If I was to access this from a content page that inherits the main master all is great but the idea was to have a master page that contains side bar.
Now my side.master inherits from main master:
public partial class RWCMSSide : System.Web.UI.MasterPage
{
//Create property for nested master
public Business.BusinessEntities.User LoggedOnUser { get; set; }
protected void Page_Load(object sender, EventArgs e)
{
//Assign main masters user to the new property
//Master.LoggedOnUser is always null
this.LoggedOnUser = Master.LoggedOnUser;
}
}
You could argue that I could recreate the user on the nested master page but then that would create two hits to the database when it could be done as one.
Whilst debugging the main master the user exists, it's just not being passed down.
Any pointers would be greatly appreciated!
Regards,
Problem
The Master's Load is executed after the Child's Load:
...
Master page Init event.
Content page Init event.
Content page Load event.
Master page Load event.
Master page controls Load event.
...
That's is why the property is null.
Solution
1. You can set it in the Init event - protected void Page_Load(object sender, EventArgs e)... if it is not dependent on the page being loaded (as it is probably).
2. Or you can turn the property into the lazy property(no need for actual Lazy<T> if it is not (and it probably should not be) intended to be used in multithreaded code):
public partial class RWCMSMain : System.Web.UI.MasterPage
{
private Business.BusinessEntities.User m_LoggedOnUse;
public Business.BusinessEntities.User LoggedOnUser
{
get
{
if (this.m_LoggedOnUse == null)
this.m_LoggedOnUse = userRepo.GetUser(securityToken);
return this.m_LoggedOnUse;
}
}
protected void Page_Load(object sender, EventArgs e)
{
}
}
Related
I have to deal with an ASP.NET project in which i have to support localization and translation.
Change of colture may happen only in InitializeCulture method of Page object and not on MasterPage.
Usually when i have to deal with common elements (header/footer) i put them in MasterPage but doing so prevent me to properly localize those elements.
So i am intereseted in understand how to template a page using a common base page that will be derived by all other pages (a sort of MasterPage).
I have found this article that explain clearly how to handle such situation, but i think is a bit outdated :
https://www.codeproject.com/Articles/2915/ASP-NET-Page-Templates-Using-Inheritance
So i would ask if there is a better approach or technology to achieve my goal.
Here a simple demo of how to send a variable to the Master Page. Put a public property in the Master named Language.
public partial class Site1 : System.Web.UI.MasterPage
{
public string Language { get; set; }
protected void Page_Load(object sender, EventArgs e)
{
Label1.Text = $"My language is {Language}.";
}
}
Then add a property for the Master in the normal page and cast Page.Master to your Master Page's partial class (Site1 by default).
public partial class Default1 : System.Web.UI.Page
{
public Site1 master;
protected void Page_Load(object sender, EventArgs e)
{
master = (Site1)Page.Master;
}
Then you can access Language in the Master from the Page.
master.Language = "nl-NL";
I have a class that populates variables based on user information (checks AD, loads e-mail, distinguishedName, description field, etc etc). I declare the 'currentinfo' variable in the _Default Page, so I could hopefully have the object throughout the session.
I instantiate the class in the Page_Load event, but inside an If(!IsPostBack) so the constructor method runs only the first time. It works fine (the constructor populates my object and all the data is inside it as confirmed in debug mode with breakpoints). But when it leaves the If clause, the object becomes null again.
I wanted to have the object ready when the page loads so I could use it in other events, like button clicks. So, my questions are:
1 - I use the if(!IsPostBack) clause because my constructor takes some time to finish and everytime I click on a button it loads the page again and the object is instantiated if it´s not inside the if clause, so, how do I stop ASP.NET from reloading the page at every new event?
2 - If 1 is not possible how do I keep my object valid after it leaves the clause?
EDIT: 2 - How do I keep the variable state after the page loads for a second time?
public partial class ListUsers: System.Web.UI.Page
{
CurrentUserStructure currentuserinfo;
List<CurrentUserStructure.ListUserClass> lsUsers;
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
currentuserinfo = new CurrentUserStructure();
lsUsers = currentuserinfo.GetUserList();
}
}
I guess you need viewstate to save the List
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
List<User> listUser = new List<User>();
listUser.Add(new User() { Name = "U1" });
listUser.Add(new User() { Name = "U2" });
listUser.Add(new User() { Name = "U3" });
ViewState["listUser"] = listUser;
}
}
protected void Button_Click(object sender, EventArgs e)
{
var list = ViewState["listUser"]; //you can get the List from the ViewState
}
and you need Serializable your class
/// <summary>
/// you need Serializable the class so that you can save it in ViewState
/// </summary>
[Serializable]
public class User
{
public string Name { get; set; }
}
If you use a Server side control, a Postback would always occur. So, you cannot stop ASP.NET from reloading the page at every new event. However, you can use the IsPostback Property to ensure that the variables are loaded the first time the page loads and on subsequent request the initialization code does not execute.
To Keep the variable state, you may either store the variable in a Session or in Page ViewState.
In the following code, I have added the property ListOfUsers and stored in session. The value is set first time at page load and subsequently the value can be read from Property.
public partial class ListUsers : System.Web.UI.Page
{
// the object is declared here.
// I understand it should be valid even if the page loads again
CurrentUserStructure currentuserinfo = new CurrentUserStructure();
private List<CurrentUserStructure.ListUserClass> ListOfUsers
{
get {
return Session["CurrentNamespace.ListOfUsers"] ?? new List<CurrentUserStructure.ListUserClass>();
}
set {
Session["CurrentNamespace.ListOfUsers"] = value;
}
}
protected void Page_Load(object sender, EventArgs e)
{
// everything from here on should happen only
// the first time the page is loaded
if (!IsPostBack)
{
// bellow the lsUser object is constructed
this.ListOfUsers = currentuserinfo.GetUserList();
} // up to here the lsUsers object is available
}
You should store session data in the Session item collection (see How to: Save Values in Session State). Create an instance of your CurrentUserStructure class in the Session_Start event in the Global.asax file, rather than in the page:
private void Session_OnStart(object sender, EventArgs e)
{
HttpContext sessionContext = HttpContext.Current;
// Create a new instance and store it for future use
CurrentUserStructure newInstance = new CurrentUserStructure();
sessionContext.Session["currentuserinfo"] = newInstance;
}
Then, in your ListUsers page, add a property that will read the value from the session-store.
public partial class ListUsers : System.Web.UI.Page{
private CurrentUserStructure UserInfo
{
get
{
// Read the object from session store
return (CurrentUserStructure) HttpContext.Current.Session["currentuserinfo"];
}
}
}
As to your second question, if you need lsUsers to be available outside of the if clause, then you need to declare it above the clause. For example:
List<CurrentUserStructure.ListUserClass> lsUsers = null;
if (!IsPostBack)
{
lsUsers = currentuserinfo.GetUserList();
}
But the above probably won't be as relevant, once you implement your logic correctly. If you want to store the output of GetUserList() between requests, you have a couple of options:
If the output is required by multiple pages, it's probably best to store it in the session-store. You can do this also in the Session_OnStart event.
If the output is only required by this page, you can store the output in the page's ViewState (see How to: Save Values in View State).
In the alternative to option 1. above, it may make sense to store the value of GetUserList() in a public property inside the CurrentUserStructure class instance. For example:
public class CurrentUserStructure{
private List<CurrentUserStructure.ListUserClass> users;
public List<CurrentUserStructure.ListUserClass> Users{
get {
if(users==null){
users = GetUserList();
}
return users;
}
}
// Note that this method is now private
private List<CurrentUserStructure.ListUserClass> GetUserList() {
// Implement your logic here
}
}
This way, you'll be able to access the list from the CurrentUserStructure, which will be stored in the session-store:
protected void Page_Load(object sender, EventArgs e)
{
// No need to check if this request is a post-back, because the value is stored elsewhere and does not need to be re-queried every time
List<CurrentUserStructure.ListUserClass> lst = this.UserInfo.Users;
// Do stuff with lst ...
}
I'm using an asp.net user-control in two different aspx forms. How can I customize the events handling of the user-control depending on the calling form ?
void ComboboxCountry_SelectedIndexChanged(object sender, RadComboBoxSelectedIndexChangedEventArgs e)
{
if it is form1 that called the User-control => do process 1
if it is form2 that called the User-control => do process 2
}
Thanks.
Despite the fact if this is a good design you are trying to implement: you could add a property to your control like
public BehaviourEnum Behaviour { get; set; } // You need to implement the enum
Then you could
void ComboboxCountry_SelectedIndexChanged(object sender, RadComboBoxSelectedIndexChangedEventArgs e)
{
if (Behaviour == BehaviourEnum.Behave1) // etc.
}
The pages implementing your control would need to set the Behaviour-Property accordingly.
Edit: If your control needs to interact with the parent page, I would introduce an interface on the parents page. Then you could design something like this:
// The page containing this control needs to implement IMasterpage
public IMasterpage Masterpage { get; set; }
void ComboboxCountry_SelectedIndexChanged(object sender, RadComboBoxSelectedIndexChangedEventArgs e)
{
// Propagate the behavour to your parent page
Masterpage.CallwatheverMethodInYourInterface();
}
The goal is to propagate behavour which depends on the parent page into the parent page itself. That way you can keep your control slim and independent.
I need to be able to make an object that is instantiated in a ASP.NET Master Page to be visible to all of the pages in the application that are based on that Master page. At the moment I'm defining the object here:
public partial class Control : System.Web.UI.MasterPage
{
public User TheUser;
protected void Page_Load(object sender, EventArgs e)
... but I think that's where I'm going wrong. Can anyone help?
Are you trying to create a control that inherits from a MasterPage? What you really want to do is create a MasterPage and add a property to it:
public partial class MyMasterPage: System.Web.UI.MasterPage
{
public string MyProperty {get;set;}
}
Now, from a Page that uses that MasterPage, you can just reference the MasterPage and access its members directly:
protected void Page_Load(object sender, EventArgs e)
{
MyMasterPage m = Master as MyMasterPage;
string masterProperty = m.MyProperty;
}
You'd be better off creating a base page (that inherits from System.Web.UI.Page) that all your pages inherit from, add your TheUser object to the base page.
Please note, pages do not inherit their master pages.
I have the master page code behind like this:
public partial class TheMasterPage : System.Web.UI.MasterPage
{
string test = null;
protected void Page_Init(object sender, EventArgs e)
{}
}
When I'm in the Page_Load function in the code behind of the content page, I don't see the variable test as being available. Am I declaring it wrong?
Thanks.
Your property should be public and should have get, set
public string test
{
get; set;
}
I already answered it a little early Accessing property of master page inside content page
Having a master Page is not the same as inheriting a page class. What you would want to do is have a public property on the master page, and then access that from the content page.