Accessing control from a master page asp.net - storing the value - asp.net

At the moment I have a master page and a content page. My master page consists of a dropdownlist, from which I need to select a child from. The content page loads according the child chosen. How should I store the dropdownvalue chosen?
I don't think I can use the session, since I would like the user to be able to open multiple tabs and watch different children contents at the same time. If I can use the session in this case, I'm not sure how.
I don't think I can use the viewstate since, although it solves my multiple tabs problem, the master page and content page have a different view state.
At the moment I am using a public static variable on the content page, and I set it in the master page. But from what I've heard static variables have their values stored throughout ALL the current sessions on the site.
Question:
Can any one help me by suggesting which technology should I use?
I have also heard about the 'Application' object but I don't think it makes sense to use it.
Current working Code:
(content page)
public static string Child
{
get
{
if (child == null)
return "-1";
return child;
}
set
{
child = value;
}
}
(master page)
protected void ddlChooseChild_IndexChanged(object sender, EventArgs e)
{
ContentPage.Child = ddlChooseChild.SelectedValue;
}

The best way to share data between different controls is to make use of the "Items" collection (which is a property of the HttpContext class). The collection is a Hashtable and can be accessed from your Page and User Controls like so:
Context.Items["Child"] = ddlChooseChild.SelectedValue;

Unless you are restricting session by using PageID or something similar, Sessions are available on multiple tabs.
Check out this article, Master Content Page interaction

Related

Share data between usercontrols

On my page I have n-userControls (same control) I need to communicate between them(to be more specific I need to pass one in value) .
I don't want to involve the hosting page for that.
The controls acts as "pagers" and interact with the paged data on the hostin page via events that hosting page is subscribed to.
So when user click on one of the pager and changes it's state, the other control should know about it and change itself accordingly.
I can not use VieState because viewstate is per control and so is the controlstate.
Can I use Session for that? (session is shared and there is only one value that i need to store)
Or maybe there is something better I can use? (no QueryString)
Personally there isn't an "easy" way to do this without doing it through the controlling page, or an event.
From what you are saying what I would envision would be something like this. Assuming two controls A and B that are your pager controls.
The containing page subscribes to the "PageSelectionChanged" event on both controls, in response to that event it updates the data, which you already have, AND it enumerates through all pager controls setting the "Current Page" value.
You already have event plumbing in place for communication from control -> page, use what you already have built.
Why Not Session?
I was asked in the comments if this would be better than session, and the answer is yes, for a number of reasons.
Session information, unless explicitly cleaned up exists for the duration of a users session (typically 20 minutes)
Becase of number 1, you would need to add items to the page, for if(!ispostback) to "clear" the session variables so that the user didn't start on a different page.
Future application growth, session information has to be moved out of process to SQL Server or otherwise to work in a web farm environment, for this I try to avoid it as well.
Using session stores this information in memory on the webserver, although small (4 bytes if integer) it can add up and is un-necessary
Depending on the nature of your updates, you cannot ensure control order with session alone to ensure that 1 control forces an update to all controls.
There are other solutions, the solution similar to the one posted above that does a recursive look at the page, but you have to be careful with that to ensure that you do not get into a looping/endless recursion situation, in addition, if you have a lot of controls on the page, it can add a lot of overhead to constantly loop through everything.
The container page has a property in viewstate that stores the state. When a user clicks on one of the pager, it raises an event that is handled by the container page. This then loops through the n user controls and calls a public method on those controls.
You can build a quick modified version of the Observer Pattern. I would suggest building a manger control on the pages. But if you don't want to modify the page, here is a quick solution.
You can create a static method that will notify all of the same type of controls. By Calling their Update Method. Feel free to pass what ever data you need.
protected void control_event(object sender, EventArgs e)
{
UpdateAllControls(page);
}
public static void UpdateAllControls(Control parent /* can be Page */)
{
foreach (Control c in parent.Controls)
{
if (c.GetType() == this.GetType())
((MyType)).Update()
if (c.HasControls())
controls = GetAllControls(controls, t, c);
}
}

ASP.NET How to raise load event on previous page with cross page postbacks

I'm working on a wizard-like set of page, and I'm relying on cross page postbacks to navigate between them.
I need to be able to trigger the Load event on the previous page in order to save the form data for the page.
I've been told that for situations of this sort all I had to do is access the PreviousPage property in the destination page and this would trigger the load event of the previous page but for some reason this doesn't seem to be working.
Is there anything else I can do to explicitly trigger the load event on the previouspage if the PreviousPage property is not null?
Thanks for your help,
Yong
Have you considered moving whatever persistence logic you're doing in the load of the Previous Page into a method on the page?
That way you can just hit:
if(PreviousPage != null)
PreviousPage.DoThatSavingThing();
Obviously you'd need to type it to get the specific methods you add unless you added those to all pages.
This sounds a little confusing to me, but if you are wanting access to data, it's best to save that data into something that you can easily get to, like the ASP.NET session cache. So instead of going back to a previously navigated page in order to get data, you will cache the data the first time you reach the first page, and then when the user navigates to the 2nd page, it will have access to that information.
To add - I tested using two methods of getting a "strongly-typed" previouspage.
Added a reference to the destination:
Added the PreviousPage directive on the destination:
When accessing the PreviousPage property in the destination, the Load event was fired on the
PreviousPageName page (source).
Example (assuming there is a public property named Test on the PreviousPageName (Source page)):
protected void Page_Load(object sender, EventArgs e)
{
if (PreviousPage != null)
{
//Using a reference, you have to cast:
PreviousPageName x = (PreviousPageName)PreviousPage;
string test = x.Test;
//Using the PreviousPage directive, you do not need to cast:
string test2 = PreviousPage.Test
}
}

asp.net code behind variable

I am generating some head html in page load and because of that I query database once. in the page I query database again and put data into html with inline code.
my question is is there better way to do this? I dont want to query database everytime and reach out those filled variables from inline code. something like page.addVariable in page_load and reach those at inline like page.variables["variablename"]
thanks in advance
If I understand what you are asking, you can make an accessor and set it to Protected. That will allow you to access it from the page.
If you want to prevent calling the database on callbacks, you could always add the information to the view state on the page.
Information on the view state, hidden fields, and cookies:
http://www.csharphelp.com/archives/archive207.html
I'm not sure if this is what you're after, but you can use a HiddenField to store any data you want on the page.
Also, if you don't need it to be on the page, you can use Session or ViewState.
Here's an example of using ViewState as a property (NB. you can interchange ViewState with Session, look at the links I gave you for an explanation between the two):
public string YourProperty
{
get
{
object content = ViewState["YourProperty"];
if (content == null)
{
return string.Empty;
}
return content.ToString();
}
set
{
ViewState["YourProperty"] = value;
}
}
Note, that anything you put into ViewState or SessionState must be marked as Serializable.
If it's quite a simple class, just mark the class with the [Serializable] tag.
Is the data you retrieve from the database page specific, user specific or global to the entire application?
If the data is user specific you can use Session State.
If the data is global to the entire application you could use Application State.
Whichever you use, you can implement the data retrieval in the Session_Start (will be called only once for each user) or Application_Start (will be called only once when the web app starts) events in a Global.asax file.

ASP.net drop down dynamically styling and then remembering the styles on aborted submit

So, I've got an ASP drop down list (this is .net 2.0). I'm binding it with data. Basically, when the page loads and it's not a post back we'll fetch record data, bind all the drop downs, and set them to their appropriate values (strictly speaking we: initialize page with basic set of data from DB, bind drop downs from DB, fetch actual record data from DB, set drown downs to appropriate settings at this time). What I want to do is selectively style the list options. So the database returns 3 items: ID, Text, and a flag indicating whether I the record is "active" (and I'll style appropriately). It's easy enough to do and I've done it.
My problem is what happens when a form submission is halted. We have slightly extended the Page class and created an AddError() method, which will create a list of errors from failed business rule checks and then display them in a ValidationSummary. It works something like this, in the submit button's click event:
CheckBizRules();
if(Page.IsValid)
{
SaveData();
}
If any business rule check fails, the Page will not be valid. The problem is, when the page re-renders (viewsate is enabled, but no data is rebound) my beautiful conditional styling is now sadly gone, off to live in the land of the missing socks. I need to preserve it.
I was hoping to avoid another DB call here (e.g. getting the list data back from the DB again if the page isn't valid, just for purposes of re-styling the list). But it's not the end of the world if that's my course of action. I was hoping someone might have an alternative suggestion.
I couldn't think of how to phrase this question better, if anyone has any suggestions or needs clarification don't hesitate to get it, by force if need be. ;)
I'm not sure I completelly understand what kind of styling you apply to your drop-down items, but it seems this style is something that the control does not preserve accross postbacks. Usually this kind of info will therefore need to be saved in the ViewState.
I see two options (other than re-loading from DB):
First method: Create your own drop-down control that inherits from DropDownList. Then save styling data in the control's ViewState bag when styling the items:
public void SetItemActive(ListItem item)
{
ViewState[item.Value] = "active";
}
then override the OnRender
protected override void Render(HtmlTextWriter writer)
{
....
foreach(ListItem item in Items)
{
if ( ViewState[item.Value] == "active")
{
** RenderActiveItem **
}
else
{
** RenderNormalItem **
}
}
Second method: is to save the active ID's in the Page's ViewState then re-style the dropdown on each postback using the data from the ViewState rather than from the DB
Well, I couldn't come up with anything except to go to the database to re-retrieve my list data when the Page was not valid, and re-style the control.

What is the most efficient way for a control to determine if it's rendering in a Web form or a master page?

I have a control that can be placed in a Web form (.aspx) or a Master Page (.master). I want it to function differently depending on which one it's in.
My first thought is to climb the control tree back to the root and see if I cross over a MasterPage control. If so, then it would have to be in the Master Page.
But, this seems inefficient. Is there a better way?
First check if the page has a master page at all. Then go through the control tree to look for a content place holder:
public static bool IsInMaster(Control control) {
if (control.Page.Master == null) return false;
while (control != null) {
if (control is ContentPlaceHolder) return false;
control = control.Parent;
}
return true;
}
I am not sure if there is a more efficient way, but if you are climbing up the hierarchy, do so through NamingContainer. You will skip plenty of unnecessary hops by using that.
Unless is a control that will appear lots of time on the page, going through the NamingContainer will be more than enough :)

Resources