I've got an ASP.net application that is used to display information queried from our ERP system onto various web pages. The main object is called an EpicorUser, and it basically encapsulates all current information about an employee.
This object is used to fill in a bunch of various fields on the master page such as Full Name, current activity, clock in/out times, etc.
I am trying to pass this object from the MasterPage into the content pages to avoid needlessly querying the WebService that serves this information. The problem is, when I access the object from a ContentPage, it is always null. I know it has been populated because my MasterPage content is all filled in correctly.
I am trying to access the MasterPage 'CurrentUser' object from my ContentPage like this:
**MasterPage Codebehind:**
public EpicorUser CurrentUser; //This object is populated once user has authenticated
///This is in my ContentPage ASPX file so I can reference the MasterPage from codebehind
<%# MasterType VirtualPath="~/Pages/MasterPage/ShopConnect.Master" %>
**ContentPage CodeBehind:**
string FullName = Master.CurrentUser.UserFileData.FullName; //CurrentUser is null(but it shouldn't be)
Strange thing is, I had another content page where this system worked fine. It has also stopped working, and I don't think I have changed anything on the masterpage that could cause this. I had set the CurrentUser as a public property so I could access
I went as far a creating a method to re-populate the object from the master page, and calling it from the code-behind on the contentpage:
**ContentPage code-behind:**
EpicorUser CurrentUser = Master.GetCurrentUserObject();
**MasterPage Method being invoked:**
public EpicorUser GetCurrentUserObject()
{
using (PrincipalContext context = new PrincipalContext(ContextType.Domain, "OFFICE"))
{
UserPrincipal principal = UserPrincipal.FindByIdentity(context, HttpContext.Current.User.Identity.Name);
EpicorUser CurrentEmployee = RetrieveUserInfoByWindowsID(principal.SamAccountName);
return CurrentUser; //Object is NOT null before the return
}
}
**ContentPage code-behind return:**
EpicorUser CurrentUser = Master.GetCurrentUserObject(); //But object is now null once we return
Stepping through the code shows me that the CurrentUser object is populated correctly in the MasterPage code behind, but once it is returned to the ContentPage code behind, it is now null!
Anyone know where the disconnect is?
Content Page is loaded first and then Master page will be loaded. So, your property could be blank when it is accessed in the content page. You can try creating a public method(to return UserObject) on the master page and then call the method from content page.
Another option is
creating a base page class(inherit all content pages) and create a property to return the user object. So, all pages can access the value
EDIT:
public class BasePageClass : System.Web.UI.Page
{
public List<string> LookupValues
{
get
{
if (ViewState["LookupValues"] == null)
{
/*
* create default instance here or retrieve values from Database for one time purpose
*/
ViewState["LookupValues"] = new List<string>();
}
return ViewState["LookupValues"] as List<string>;
}
}
}
public partial class WebForm6 : BasePageClass
{
protected void Page_Load(object sender, EventArgs e)
{
}
protected void MyButton_Click(object sender, EventArgs e)
{
//access lookup properties
List<string> myValues = LookupValues;
}
}
Related
I hope you can help me with this. I am creating an internal webforms asp.net site to display a list of internally used documents in different categories.
I decided to create a custom document class to put in a list to hold the documents, and then a custom web user control to display the documents wherever they want them on the site.
The documents class is in a general class file in my App_Code folder.
cabinet.cs
public class Document
{
private string _Url;
private string _Title;
public Document(string URL, string Title)
{
_Url = URL;
_Title = Title;
}
public string URL
{
get { return _Url; }
set { _Url = value; }
}
public string Title
{
get { return _Title; }
set { _Title = value; }
}
}
This code works just fine. Then in my user control I create a list of type document and initiate it in Page_Load(). Then I created a public method to add new documents to the list.
DocDisplay.ascx.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
public partial class DocDisplay : System.Web.UI.UserControl
{
private List<Document> _DocList;
protected void Page_Load(object sender, EventArgs e)
{
_DocList = new List<Document>();
}
public void Add(string URL, string Title)
{
_DocList.Add(new Document(URL, Title));
}
public void WriteDocuments()
{
foreach (Document doc in _DocList)
{
Response.Write($"<span class='document'><a href='{doc.URL}'>{doc.Title}</a></span>");
}
}
}
I am getting the error in the add method. It says that my object is not to an instance of an object. But I do that in Page_Load.
index.aspx.cs
protected void Page_Load(object sender, EventArgs e)
{
pageDocs.Add("index.aspx", "Hello World!");
pageDocs.Add("index.aspx", "Red Rum");
pageDocs.Add("index.aspx", "Lorum Ipsum");
}
I have registered my user control in my index page.
<%# Register Src="~/DocDisplay.ascx" TagPrefix="uc" TagName="DocDisplay" %>
<uc:DocDisplay ID="pageDocs" runat="server" />
So I am not exactly sure why I am getting that error. As far as I can tell, there is nothing wrong with my code. If you could help I would greatly appreciate it.
Events get fired starting from the root of control hierarchy and end at the leaf nodes. Index.Page_Load is being called before DocDisplay.Page_Load has an opportunity to instantiate the list.
The _DocList field needs a value before it can be used by anything, so initialization needs to happen as early as possible. This is accomplished very easily with a field initializer. Declare and assign it all at once:
private List<Document> _DocList = new List<Document>();
When the Index class instantiates its child controls early in the page life cycle, _DocList will immediately have an object reference.
It's tempting to say, "Page_Init will be called sooner; I'll do it there." This may work at first, but if you do any dynamic control loading, you'll soon find out that it's a balancing act. A dynamically loaded control has to play event catch-up, so its Init event can be fired after statically loaded controls have started firing Load events. It's important to use each event for its purpose, and not for its timing, and use constructors (and field initializers) to initialize non-control class state.
I created a nested master page. The parent master page A inherits from System.Web.UI.MasterPage. The child master page B inherits from A.
I then created a web content page C which uses master page B, and inherits from System.Web.UI.Page.
From the web content page C I am able to access variables and methods from within both master pages. However the problem lies in accessing the parent master page variables and methods.
The problem is that a NullReferenceException is being raised. Variables and methods are not being initialised.
What is a possible solution?
public partial class ParentMasterPage : System.Web.UI.MasterPage
{
internal Button btn_Parent
{
get { return btn; }
}
}
public partial class ChildMasterPage : ParentMasterPage
{
internal Button btn_Child
{
get { return btn; }
}
}
public partial class WebContentPage : System.Web.UI.Page
{
protected override void OnInit(EventArgs e)
{
Button tempA = Master.btn_Child; //WORKS
Button tempB = Master.btn_Parent; //NULL REFERENCE EXCEPTION
}
}
A nested master page does not inherit it's parent master page's type. Instead it composes itself such that the NestedMasterType.Master property is an instance of the parent master page. The NestedMasterType type still inherits from System.Web.UI.MasterPage.
So this is right:
public partial class ChildMasterPage : System.Web.UI.MasterPage
This is wrong:
public partial class ChildMasterPage : ParentMasterPage
You would then access the (parent) Master of the (child) Master of a Page (that uses the child master) like this:
Button tempA = ((ChildMasterPage)this.Master).btn_Child;
Button tempB = ((ParentMasterPage)this.Master.Master).btn_Parent;
Note: This answer assumes that you mean that ChildMasterPage is a nested master page, that uses a Master directive similar to the below:
<%# Master MasterPageFile="~/ParentMasterPage.Master" Inherits="ChildMasterPage"...
A Page only has a reference to it's immediate master and it's variables, you would have to traverse up the object graph to the main master page i.e.
var parentMaster = (ParentMasterPage)Page.Master.Master;
parentMaster.SomeProperty = ...;
Alternatively, you could bridge the gap between the 2 by implementing the same property in your ChildMasterPage i.e.
internal Button btn_Parent
{
get { return ((ParentMasterPage)Master).btn_Parent; }
}
This would mean the code you currently have would work, however, it sort of defeats the purpose of having a main master page.
common class file common.cs: This file, I have added by clicking add->new items-> class
public class common
{
public int v,n;
public int da()
{
return n= v;
}
}
Another file: It's an webpage file name is a1.aspx.cs:
common c = new common();
c.v = Convert.ToInt32(TextBox1.Text);
c.da();
Response.Redirect("ulogin.aspx");
the value from a text box stores in c.v variable
So, now, I want the value which was given in the textbox1.text in another webpage file named as ulogin.aspx.cs
I used this code:
common d=new common();
d.da();
Label1.Text = Convert.ToString(d.n);
but after running it shows the value as 0.....
In a web application, you'll need to persist the information somewhere common (typically Session for per user info or Application for per application info) so that it can be used between different pages & user controls in your application.
I'd suggest adding a Session backed property to your page & usercontrol which accesses a common Session["variable"]. Something like the following.
(i.e. lets imagine your code was being exectued on a button click)
a1.aspx.cs
public int ValueToStore
{
get
{
return Session["ValueToStore"] != null
? (int)Session["ValueToStore"]
: 0
}
set
{
Session["ValueToStore"] = value;
}
}
protected void Button1_Click(object sender, EventArgs e)
{
ValueToStore = Convert.ToInt32(TextBox1.Text);
Response.Redirect("ulogin.aspx");
}
ulogin.aspx.cs
public int ValueToStore
{
get
{
return Session["ValueToStore"] != null
? (int)Session["ValueToStore"]
: 0
}
set
{
Session["ValueToStore"] = value;
}
}
protected void Page_Load(object sender, EventArgs e)
{
Label1.Text = ValueToStore.ToString();
}
As you can see, you now have some code duplication between the two pages, so the next step would be to consider implementing a basepage which as the common property, and then inherit that from a1.aspx & ulogin.aspx.
i.e.
public class a1 : BasePage
{
...
}
public class ulogin : BasePage
{
...
}
public class BasePage : System.Web.Page
{
//Put ValueToStore property here.
}
There are many users visiting same page, they may set different value, and the expected result is whatever value is set by an user on Page 1 need to be displayed in Page 2.
Any Web technology is stateless as they use HTTP which is stateless again.
However there are many ways to get this done, each method has their own advantages.
--Session--
Please use session variable to store your value, which is a kind of variable.
Each user has different session variable to store, and its available
Until the user logs out (i.e. till Session is available)
Storage: Server Memory
public class Common
{
public int? Data
{
get
{
if(Session["Data"]!=null)
{
return int.Parse(Session["Data"].ToString());
}
return null.
}
set
{
Session["Data"]=value;
}
}
}
--Query String--
You can pass value from one page to another page using query string.
Page 1
int value=1;
Response.Redirect("Page2.aspx?data="+value.ToString())
Page 2
if(!string.IsNullOrEmpty(Request["data"]))
{
int value=int.Parse(Request["data"]);
}
--Posting--
You can also post the value from one page to another page.
Page 1 (html)
<form action="page2.aspx" method="post">
<input type="hidden" name="data" value="1"/>
</form>
Page 2
if(!string.IsNullOrEmpty(Request["data"]))
{
int value=int.Parse(Request["data"]);
}
There are even more ways... You have to select what is suitable for your scenario.
Read ASP.NET State management
http://msdn.microsoft.com/en-us/library/75x4ha6s.aspx
If the page ulogin.aspx is designed to be always redirected from a1.aspx, then set the PreviousPageType in ulogin.aspx and get the previous page values by this.PreviousPage instance. (Cross-Page-PostBack)
Convert member v to a property of common. Store common into a Session variable. And once you are ready to get the value, cast session variable to common and access v property from there.
Alright, I am trying to accomplish this: When a user clicks a button that is on a ascx web user control with text boses, it first displays a DIV that is hidden, this div contains a ascx web user control. Basically I want that web user control to grab what they typed in the boxes on the first web user control, and then apply to a SQL search from what the users type in the text boxes on the first page. Is this possible or do I need to rethink my strategy on this? I am programming in c# for the SQL statements.
It is possible.
You can define properties of the control which accepts the text input, and expose the values using direct field access, variables, or session variables; you can then use FindControl from within the newly displayed control, and, if found, utilise the now exposed properties to gather the values required.
For instance, your input control code-behind might look something like this:
partial class MyControl : UserControl
{
public string MyFieldValue
{
get { return MyFieldTextBox.Text; }
}
}
And in the next control, to use it, a little like this:
partial class MyControl : UserControl
{
protected void Page_Load(object sender, EventArgs e)
{
var myControl = Page.FindControl("MyControlInstanceName") as MyControl;
if (myControl != null)
{
var myFieldValue = myControl.MyFieldValue;
}
}
}
Is the 2nd user control embedded in the 1st or not?
If not, you can make anything available upwards between user controls by simply adding public properties to your user controls. This means they can then be accessed from the page level or the containing user control. For example, if I have UCA, UCB, UCC
UCA contains UCB and UCC is hidden.
UCB has the following property
public string UserEnteredName
{
get { return NameTextBox.Text; }
}
UCC has the following property and method
public string UserEnteredName { get; set; }
public BindResults()
{
UserEnteredLiteral.Text = UserEnteredName;
}
Then tie it together with UCA:
protected MyButton_Click(object sender, EventArgs e)
{
UCC.UserEnteredName = UCB.UserEnteredName;
... some logic herre.
UCC.BindResults();
}
You can also raise an event from UCB that can be responded to in UCA if your button or submit action exists in UCB.
How can I pass user control properties to the page AND make these properties available to all methods on the page (and not just to one method that is fired on a control action, e.g. onControlClick)
I have a set up of essentially 3 pages:
user control (ascx/cs)
class (cs) - that contains user control properties
host page (aspx/cs) - references the user control
The user control consists of 3 interrelated dropdowns. I'm having success passing these dropdown values through a class onto the page via an event that is fired when a user clicks on the dropdown menu. So this way the host page is continously aware of the values in the user control. However, I want the page to use the control's properties (stored in a class) on all of its methods - how do I make this user control class available to all?
Also I'm using ASP.NET and C# by the way.
Here's the Code (not sharing the full code here - just the snippets of a similar code block)
On the ASPX for Menu Host Page:
<linked:LinkMenu2 id="Menu1" runat="server" OnLinkClicked="LinkClicked" />
Host Page (cs):
protected void dropdownclicked(object sender, ddtestEventArgs e)
{
if (e.Url == "Menu2Host.aspx?product=Furniture")
{
lblClick.Text = "This link is not allowed.";
e.Cancel = true;
}
else
{
// Allow the redirect, and don't make any changes to the URL.
}
}
Host Page (aspx)
<asp:dropdowncustom ID="dddone" runat="server" OnddAppClicked="dropdownclicked" />
Control (cs)
public partial class usercontrol_tests_dropdown1 : System.Web.UI.UserControl
{
public event ddtestEventHandler ddAppClicked;
}
public void selectapp_SelectedIndexChanged(object sender, EventArgs e)
{
ddtestEventArgs args = new ddtestEventArgs(selectlink.SelectedValue);
ddAppClicked(this, args);
}
Class:
public class ddtestEventArgs : EventArgs
{
// Link
private string link;
public string Link
{
get { return link; }
set { link = value; }
}
public ddtestEventArgs(string link)
{
Link = link;
}
}
public delegate void ddtestEventHandler(object sender, ddtestEventArgs e);
Hopefully this is what you're after. The best way to do it is to expose your controls as public properties from your user control. So, in your user control, for each drop down list add a property:
public DropDownList DropDown1
{
get { return dropDownList1; }
}
public DropDownList DropDown2
{
get { return dropDownList2; }
}
You can do the same for any other properties you want to access on the host page:
public string DropDown1SelectedValue
{
get { return dropDownList1.SelectedValue; }
set { dropDownList1.SelectedValue = value; }
}
Then, from your host page you can access the properties through the user control:
string value = UserControl1.DropDown1SelectedValue;
or
string value = UserControl1.DropDownList1.SelectedValue;
Here's a couple of other answered questions that you might find useful as I think (if I've understood correctly) this is what you're doing:
Getting data from child controls loaded programmatically
How to change the value of a control in a MasterPage.