Is MasterPage -> Page -> UserControl the loading order of an ASP .NET request?
Is there a situation where an UserControl loads before the Page loads ?
I have private messages for my users and in every page they will see a message like this "You have 3 unread messages."
When users view an unread message I want to change the message to this "You have 2 unread messages."
This can be easily done with a Request.Redirect, but I want to avoid this.
message 1 -> click on it will goes to MarkAsRead.aspx?id=x wich redirects me to ViewMessage.aspx?id=x
Instead of doing this I want to mark the message as read from ViewMessage.aspx?id=x then decrease my Session variable "unreadMessages", then let my UserControl display the new number.
But my concern is that UserControls may not always load last.
The event progression in ASP.NET is as follows:
Page.OnPreInit()
UserControl.OnInit()
MasterPage.OnInit()
Page.OnInit()
Page.OnInitComplete()
Page.OnLoad()
MasterPage.OnLoad()
UserControl.OnLoad()
Page.OnLoadComplete()
(page event handlers fired here)
Page.OnPreRender()
MasterPage.OnPreRender()
UserControl.OnPreRender()
Page.OnPreRenderComplete()
Page.OnSaveStateComplete()
UserControl.OnUnload()
MasterPage.OnUnload()
Page.OnUnload()
To accomplish what your trying to do, handle your message count update in your Page.Init event, then display that count during the UserControl.Load event. I've provided the full progression of events above, which may provide you more options in case the above scenario isn't adequate. (For example, you could update the count in Page.Load, and render it in UserControl.PreRender, if for some reason Page.Init was too soon.)
check this diagram for asp.net event order.
my suggestion: implement a public void UpdateInfo() in your UserControl which is called from both the UserControl's OnLoad() event and from the OnLoad() event in ViewMessage.aspx after it adjusts the counter for unread messages.
I would agree with the above answer - it can become very tricky when you rely on child user control load events. Consider how all the MS databound controls work - you need to tell them to Bind before they will perform their function.
Related
Joined a company that use Asp.Net, a tech that I had never worked with before. I have a very simple task to do which is to change a label's text depending on a value that is included in the logged in user's session.
I considered Init, Page Load and PreRender and ended up placing my code in the PreRender event and got a comment in a code review from the main code reviewer saying "this does not belong here, go and investigate the page lifecycle to figure out why"
According to the docs:
Init should be used to "initialize control properties" (which seems to be about right for this case).
Page Load should be used to "set properties in controls and to establish DB connections".
PreRender should be used to "make the final changes to the page or its controls"
I can't see an obvious event that should be used instead of the others. I wrote above that Asp.Net is new to me so I may be missing something.
Which event should be used in this particular case, and in general, to change properties of controls?
I have a UserControl A that has to be loaded first and after that completes loading, I need to load a UserControl B.
I prefer to add both these user controls on the page at compile time (would like to avoid dynamic loading if possible).
If I add user controls on the page at compile time and set visible to false for User Control B, does it still execute the B's code behind? I can then set the visibility to true after loading User Control A
Should I be using events/delegates for notifying the completion of loading User Control A?
Don't load everything in the page event in control b, just put a method on control b to be called. Then add an event to control a which the page consumes, when the event is raised, call the load method on control b.
Edit: SampleCode
Ok so for example, create
a ASPX page
2x user controls
Put both user controls into the aspx page.
<cc:control1 runat="server" id="control_one" />
<cc:control2 runat="server" id="control_two" />
Then in control 1, create a delegate and event.
public delegate void MyCustomEvent (EventArgs args);
public event MyCustomEvent MyEvent;
protected void Page_Load(object sender, EventArgs e)
{
MyEvent(e);
}
So I have the event raised on page load. So you would have your logic in there thats required, when your done, calls MyEvent event.
In the page you want to add a handler for that event so when it's called you can do something with it.
protected override void OnInit(EventArgs e)
{
control_one.MyEvent += new WebUserControl1.MyCustomEvent(control_one_MyEvent);
base.OnInit(e);
}
void control_one_MyEvent(EventArgs args)
{
control_two.MyCustomLoad();
}
So when the page is initialized I add the event handler. In the event handler I call a custom method on the second control to load stuff.
Then in the second control I have:
public void MyCustomLoad()
{
//Stuff only loaded when event is raised and calls this method.
}
So this allows control 1 to load something, say it's done, when the page knows it's done, it can tell control 2 to do something.
Edit: After discussing this with a friend I'll explain what I mean by controlling the order.
You cannot control the order of page-life-cycle events. i.e: You can't have Control A, run through all it's page-life-cycle events, then once it's done, have Control B run through all it's page-life-cycle events.
If you do-away with the page life cycle, you can do a degree, as my example above shows, create a way of controlling the order in which the controls are rendered. By raising an event(s) at certain points when Control A is finished, you can tell Control B to do something.
The intermediate between the two controls is the page which handles the events raised by Control A which calls a method on Control B. You (well you can hack around to do it) can't specifically make Control A tell Control B to do something because that creates a direct dependency between the two controls which is bad.
Yes, the code behind will still run
Events could be useful
But if your controls have a specific dependency on each other, maybe they should just be a single control?
This is a fatally-flawed design. You should design your UI so that it doesn't matter in what order the controls load. The order in which controls load is outside of your control.
To address "Phill's" issue with an Order/Orderlines control pair:
I assume that the Order control was developed because it's useful by itself. I assume that OrderLines was developed to be able to show the line items for a given order displayed by the Order control.
I contend that there should be a single, composite control which combines Order and OrderLines. this control will pass to the OrderLines control, a DataSource consisting of the line items it is to display. This makes OrderLines independent of any other control - it simply displays the data it is told to display. It has no idea where that data came from.
Note that this can extend to a typical grid / detail / detail lines scenario, where you pass the grid a set of orders; when selected, a particular grid row will pass the Order control the selected order; when its' time to display the line items, pass the line items collection of the current order to the OrderLines control, etc.
This leaves each control with nothing to do but the Single job it is Responsible for.
"I have a UserControl A that has to be loaded first and after that completes loading, I need to load a UserControl B.
I prefer to add both these user controls on the page at compile time (would like to avoid dynamic loading if possible). "
I would suggest using WebFormsMVP: -
http://webformsmvp.com/
http://wiki.webformsmvp.com/index.php?title=Main_Page
As well as being a good implementation of Model-View-Presenter, one of the most useful features of this framework is its support for Messaging.
In a nutshell, you create Message Types, and your usercontrols (views) can post messages of whichever type you need to a message bus. Other controls can subscribe to messages of a particular type and the WebFormsMVP framework will ensure they are delivered.
This allows you to handle interaction between usercontrols by messaging publish & subscribe, without worrying about which order they load in.
Your only other option is to use dynamic control loading because, as others have pointed out, you can't rely on the order in which ASP.NET loads controls into a container.
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);
}
}
what is the advantage of raising and event in asp.net user controls?
To allow someone else to execute code when you do something, without having to poll your state to know what you've done.
The purpose of raising an event is typically to inform about something that has happened or is about to happen in the code, in order to allow other parts of the program to react on this. Usually the events are designed in a way so that the code that raises the event works the same way regardless of whether there are any listeners (event handlers) attached or not.
One example would be the click event of a button. When the user clicks the button, the button will raise a click event, which will allow any attached event handler to do something. But if there is not event handler attached, the button will not change its behavior (it's just that nothing will happen).
Though most events are raised to inform that something has happened, there are some events that are raised in order to inform that something is about to happen. Sometimes these event use an EventArgs class with read/write properties (as opposed to readonly properties which are more commonly found in EventArgs classes) which allows the event listener to communicate data back to the event-raising code. I can't come up with any good asp.net example from the top of my head, but in the winforms world a typical example of this would be the Form.Closing event, where the event handler can set e.Cancel = true to prevent the form from closing.
So, in a user control it would be useful to raise an event whenever it may be of interest for external code (typically the page) to react on something that happens within the control.
To add to the other answers already here, let me use an analogy to explain events.
Suppose you wish to receive newspapers each day. You telephone the newspaper company to inform them that you wish to receive any new newspapers they may print - you 'subscribe' to the newspaper. The newspaper delivery people maintain a list of people who are subscribers - people who should receive the paper. When the newspaper is printed each day, if you are on the subscriber list, you will receive a newspaper.
Now, suppose you have an object - a button, for instance. Suppose you want to know when that button is pressed. You 'subscribe' to events - specifically an 'OnClick' or 'OnPressed' or whatever it may be named in your language of use. Whenever the user clicks the button, the button goes through its list of subscribers, and calls the function supplied to each. These are the 'event handlers'. These functions are what the subscribers want to have called when the event occurs. In English, the subscriber might say "When you're pressed, call MyOnClick() function."
Events are used in many programming paradigms to cope with complexity - events do not need to know anything about event handlers, and vice versa. This allows for looser coupling, and more modular, reusable code.
I suggest you read about the Observer Pattern, as this is the foundation for events and event handlers.
I'm writing my first app with ASP.NET MVP (attempting Supervisory Controller) and Unit Testing (better late than never!), and I've run into a bit of a dilemma. I've written 3 User Controls, all tested and Interfaced up, Presenters in tow. Now I have come to a Page which takes these three User Controls and encountered the following problem:
User Control 1 is DateSelector, it's a Calendar control with a couple of other buttons/lists. Nothing real exciting.
User Control 2 is DailyList. Guess what it is. Anyway, you can select/delete etc.. if you select an item from the gridview, it needs to populate User Control 3.
User Control 3 is ItemDetail. Here are the DropDownLists, TextBoxes, etc... some with existing dependencies on others (selecting an option in DropDown one affects the options in DropDown 2).
If I select a new Date from my DateSelector, do I raise the event from the DateSelector Presenter? I have to somehow let the other User Controls know that a new date was selected, so that they can rebind their data, but how? If I use the Page's Presenter to subscribe to the Presenters of the User Control Views, will I not be blatantly breaking the Law of Demeter (exposing the Presenters as Properties through their Views)? Mustn't I use the Page's Presenter as the All-Knowing Controller of the page? Is there something I am missing?
Everything I've read so far says, "MVP is great, even with User Controls", but the use of User Controls is conveniently forgotten about when it comes to examples. It appears to me MVC would more closely match my pattern of thinking on this one, but currently, MVC is not an option. Any help would be great here. Thanks in advance.
The Page Presenter has to be the one to coordinate the interactions between the controls on the page. Who else would do it? I'd have the page presenter listen in on the event of the DateSelector user control. From the page presenter's perspective, it probably doesn't need to know who raised the event (view or presenter) as it looks at the DateSelector as a fully encapsulated control. The internal workings should be hidden from the page's presenter.
All it knows is that the DateSelector user control raised an event, and now it needs to notify the other controls on the page, either by raising its own event, or by explicitly calling methods on the presenter.