I am having three master pages like Master-Green, Master-Bule, Master-Red. In each master page having three buttons named as green, blue and red.
Now my default master is green,
It's assigned a page Default.aspx. At this time three button also display on the top.
How to make so clicking "blue" button means the Master-Blue shold be master page for the current page?
In the Master Page use input type submit button
<input type="submit" name="btnGreen" value="Green" />
<input type="submit" name="btnBlue" value="Blue" />
2.Then from the code behind you can check the name of the button clicked, in the Request object in the Page_PreInit event
public partial class Default : System.Web.UI.Page
{
protected void Page_PreInit(object sender, EventArgs e)
{
if (Request["btnGreen"] != null)
{
Page.MasterPageFile = "/Green.Master";
}
else if (Request["btnBlue"] != null)
{
Page.MasterPageFile = "/Blue.Master";
}
}
}
Dealing with dynamic master pages might look easy at first sight but it's a little tricky.
Consider the following:
A MasterPage is actually considered as a child control of the page, therefore, its life-cycle is like any other control on the page
In order to change the MasterPage at runetime, it has to be done in the PreInit event of the page (remember that controls do not have this event, therefore the MasterPage does not have it either)
As a reminder, the PreInit, Init, and Load events of the page life cycle work as follows: The page's PreInit event is fired, followed by all the Init events of the page's child controls (including the MasterPage), when all child Init events have been raised, the page's Init event is fired and finally the page's InitComplete event is fired indicating all Init events have been processed. The Load events work the other way around, the page's Load event is fired first, followed by all the child control's Load events and at the end, the page's LoadComplete event.
The Post back event that caused the page's post back is raised after all child control's Load events have been fired but before the page's LoadComplete event
In the PreInit event you do not have access to the page ViewState
Source: http://msdn.microsoft.com/en-us/library/ms178472.aspx
Quick Look:
So why is this so important?
In your example you have three buttons, each time a button is pressed, you need to change the MasterPage, but the MasterPage must be changed in the PreInit event of the page, but your button handler is processed after that, so the tricky part is to call Server.Transfer to re-process the page.
Note. Since you are allowing the user to personalize the MasterPage, you need a way store his preferences, usually you would use a cookie, or a database. In this sample I am going to use the Session object for simplicity but you can change it to fit your needs.
So this would look something like:
Master page code behind
protected void blueMasterPage_Click(object sender, EventArgs e)
{
this.Session["master"] = "BlueMasterPage";
this.Server.Transfer(this.Request.RawUrl);
}
In the page code behind
protected void Page_PreInit(object sender, EventArgs e)
{
if (this.Session["master"] != null)
{
this.MasterPageFile = string.Format("~/{0}.master", (string)this.Session["master"]);
}
}
Note: If you do not use Server.Transfer you won't see the changes to the page's MasterPage until the next time you do a post to the page
So this was tricky, and in my opinion, we should be able to do the same easier, one more time the ASP.Net page's life cycle doesn't help at all.
You can always follow the #AndreCalil suggestion about using just one master page and different CSS layouts for your site
Edit 1
One thing that I forgot to mention, is that you need to set the master page in all your pages consuming the dynamic MasterPage, so the best way to do it, is create a base page and inherit from it, and in the base page write the code in the PreInit event to set the MasterPage
Related
I am working with an ASP.NET project that was created by a team elsewhere in the company. One of the pages that I am working with features a userControl that queries the database to populate a generic field. The information from this query is then used by the parent page (that is, the page that contains the userControl) to set the selectedIndex of a dropdown.
The issue that I am having is that the parent page loads before the userControl, which means that the parent page loads before the results of the query are available. As a result, the selectedIndex of the dropdown is only ever set to a default index.
Based on jrista's answer to ASP .NET: when UserControls loads? , I understand that the page.OnLoad event fires before the userControl.OnLoad event. I also understand that there is no OnLoadComplete event for user controls, which I was hoping I could use to make an event that fires on the parent page when the user control finishes loading.
I've heard that the Pre-Render event can be used to the same effect (based on this question over on the asp forums), but is this the only approach? Is there a better way to fire an event from a userControl to the parent page when the user control finishes loading? Or is this simply not a good practice and would I be better to somehow change the code to avoid this situation?
Start by creating an interface that your page will implement like so:
public interface INotifyChildLoaded
{
void OnUserControlLoaded(Control control);
}
Then, implement that interface on your page
public class MyPage : Page, INotifyChildLoaded
{
public void OnUserControlLoaded(Control control) { ... }
....
}
Finally, during your user control load event, call the method:
public void MyControl_OnLoad(object sender, EventArgs e)
{
....
(Page as INotifyChildLoaded).OnUserControlLoaded(this);
}
Im trying to load a usercontrol dynamically on a aspx page however it works but i get postback issues?? I have a image button on usercontrol which I want to show a image however when i do click on button the page refreshes and does not show image?. I have a placeholder on aspx page and backend code i have this :
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
Control uc = Page.LoadControl("~/UserControls/Mycontrol.ascx");
placeholder1.Controls.Add(uc);
}
}
Do i need to do something in page_preinit or page_init ??
You should always reload the user control on the Page_init on each post back.
Dynamic controls added to the page must be added on every postback, not just the first one. Remove the !IsPostBack condition. Secondly, they have to be added during init or preinit, because that way, viewstate will be captured and restored properly (ASP.NET restores viewstate between init and load events).
Give the control an ID and also load the control in Page_init
uc.ID = "your id";
I am creating an user control. The user control is a div and I want to add a click event to it.
Edit:
The page that has this control on it has to handle this event.
How can I do this?
First, you need to define an event on your UserControl that allows Page that contains the UserControl to register and handle the event. For example:
public partial class MyUserControl : System.Web.UI.UserControl
{
// Event for page to handle
public event EventHandler DivClicked;
protected virtual void OnDivClicked(EventArgs e)
{
if (DivClicked != null)
DivClicked(this, e);
}
protected void Page_Load(object sender, EventArgs e)
{
// Page Load Code goes here
}
}
Note:
The next part would be easier if you were using a control that supported postbacks. However, since you want to use a div, I'll explain how to force a div to do postbacks. I'd like thank Mathew Nolton for this solution.
So, in the Page_Load method of the UserControl you need add an onClick attribute to call the ASP.NET's __doPostback() javascript function that calls the server back for your div. This is what gives a div the ability to postback to the server. In addition, to determine which control caused the postback, I supplied the div's ClientId along with some symbols to differentiate my postback from other controls. Remember when you define the div on the .ascx file it has to have an id assigned and set runat="server", to be accessible on the server side.
Ok, now by adding an onclick attribute to the div, it will postback to the server anytime its clicked. So, when a postback causes Page_Load to get called, I check to see if it was the div which caused the postback. If so, I raise the UserControl's DivClicked event to be handled by the Page.
public partial class MyUserControl : System.Web.UI.UserControl
{
// Event Definition and Raising methods
...
protected void Page_Load(object sender, EventArgs e)
{
// #### will denote this is an argument I provided.
string arg = "####" + divClickableDiv.ClientID;
// Add postback method to onClick
divClickableDiv.Attributes.Add("onClick",
Page.ClientScript.GetPostBackEventReference(divClickableDiv, arg));
if (IsPostBack)
{
// Get event arguments for post back.
string eventArg = Request["__EVENTARGUMENT"];
// Determine if postback is a custom postback added by me.
if (!string.IsNullOrEmpty(eventArg) && eventArg.StartsWith("####"))
{
// Raise the click event for this UserControl if the div
// caused the post back.
if (eventArg == arg)
OnDivClicked(EventArgs.Empty);
}
}
}
}
That should do it for the UserControl, now all you have to do is register for the DivClicked event on the page.
Unfortunately, you wont get design time support to register for the event. However, you can still add the code to the .aspx page. On the page where you drop your UserControl add an attribute to the UserControl called OnXXX where XXX is the name event. So, for my example above i would define my UserControl on the page would look like this:
<uc1:MyUserControl ID="MyUserControl1" runat="server" OnDivClicked="MyUserControl1_DivClicked" />
Now you add your handler code to the Page's codebehind file (assuming your using codebehind) like this:
public partial class MyPage : System.Web.UI.Page
{
// Called whenever div in MyUserControl is clicked.
protected void WebUserControl1_DivClicked(object sender, EventArgs e)
{
// Handle Div click event here.
}
}
That should do it. I hope this post helps you.
<div runat="server" onserverclick="MyClickHandler">
...
</div>
Rocka's answer is close, but not quite right (as in it didn't work for me, and I figured out why).
The code bits for the Rocka's usercontrol are fine:
// Event for page to handle
public event EventHandler DivClicked;
protected virtual void OnDivClicked(EventArgs e)
{
if (DivClicked != null)
DivClicked(this, e);
}
When consuming the UserControl, the following will not work:
the OnDivClicked is not the event handler, it's a function, so you can't assign it. let alone, when the function fires, the actual event handler variable is null, so it's not going to execute anything.
The proper way would have been:
This would have assigned MyUserControl1_DivClicked to be the handler for DivClicked. Sadly, this wasn't actually working, so in the code-behind on the page's Page_Load, put this line instead:
this.MyUserControl1.OnClick += new EventHandler(MyUserControl1);
Also, as a side note, if you make the div be runat="server", then OnClick is exposed as an event that you could have hooked into. All you would have needed is a passthru property for EventHandler in the user control to the div.
In your ItemTemplate USE asp:Panel INSTEAD OF div tag (a panel renders as a div) and set the Visibility property like so:
<asp:Panel ID="ImgFeatured" runat="server" CssClass="featured-ribbon"> </asp:Panel>
Code behind
Panel ImgFeatured = (Panel)e.Row.FindControl("ImgFeatured");
ImgFeatured.Visible = true;
I have a page and a user control — we'll call them Detail.aspx and Selector.ascx.
Let's say the page shows the details of individual records in a database. The user control basically consists of a DropDownList control and some associated HTML. The DropDownList displays a list of other records to switch to at any time.
When the DropDownList fires its SelectedIndexChanged event, I'd like the parent page, Detail.aspx in this case, to handle it. After all, he'll need to know what was selected so that he can appropriately change the URL and the details shown, etc.
To do that, I've done what I usually do, which is also what the top answer says to do in this StackOverflow question:
public event EventHandler DropDownSelectedIndexChanged
{
add
{
MyDropDownList.SelectedIndexChanged += value;
}
remove
{
MyDropDownList.SelectedIndexChanged -= value;
}
}
The above code appears in the Selector.ascx.cs codebehind file.
As a result, on Detail.aspx, I can use it like so:
<cc1:RecordSelector ID="RecordSelector1" runat="server"
OnDropDownSelectedIndexChanged="RecordSelector1_DropDownSelectedIndexChanged" />
So far nothing fancy or surprising.
Here is my problem:
This causes a NullReferenceException when the browser hits Detail.aspx.
Debugging the problem shows that when the page is first hit, the public event I've shown above tries to add the event, but MyDropDownList is null, thus throwing the exception. From what I can tell, the events are added (or attempted to be added) before the Selector user control's Load event fires and thus also before the DropDownList's Load event fires.
Curiously, if I omit the OnDropDownSelectedIndexChanged attribute from Detail.aspx and instead put the following in the Page_Load event in Detail.aspx.cs:
protected void Page_Load(object sender, EventArgs e)
{
RecordSelector1.DropDownSelectedIndexChanged += new EventHandler(RecordSelector1_DropDownSelectedIndexChanged);
}
It works exactly as expected. The events are attached and handled just fine. No problems.
But this means several bad things:
I have to remember not to use the designer to add said event onto my user control
I have to remember not to add the event via attributes when working in source view
Worst of all, as the control's author I need to make sure everybody else using my control knows 1 and 2
So what am I doing wrong? Every example I've seen thus far shows similar usage of exposing child controls' events through a user control.
The reason this works:
protected void Page_Load(object sender, EventArgs e)
{
RecordSelector1.DropDownSelectedIndexChanged
+= new EventHandler(RecordSelector1_DropDownSelectedIndexChanged);
}
and this does not:
<cc1:RecordSelector ID="RecordSelector1" runat="server"
OnDropDownSelectedIndexChanged="RecordSelector1_DropDownSelectedIndexChanged" />
is because the first one adds the handler after the control has been initialized (via the page's Init). The second example gets parsed much earlier and as such the page is attempting to add the handler before the control has initialized.
Due to the nature of the page's life cycle I think you may have to live with adding the event handler in the code-behind. There will be no way to add the handler before the control is initialized because that control will always be null prior to initialization.
I have a user control that needs to load a child control when a button is clicked.
The trouble is that it has to request the control from another class.
So in the button click event, I call the function to get me my control, and add it to the page, like this:
UserControl ctrl = ExampleDataProvider.GetControl(some params...);
myDetailPane.Controls.Add(ctrl);
The GetControl method looks like:
public static UserControl GetControl(some params...)
{
ExampleDetailPane ctrl = new ExampleDetailPane();
ctrl.Value = "12";
ctrl.Comment = string.Empty;
return ctrl;
}
This isn't working due to the page's lifecycle - the Page_Load of the child control gets fired and its controls are null.
I kind-of know that my approach is wrong and why, but don't know the best way to go about fixing it! Could anyone help?
Dynamic controls must be re-created on every postback, this Article is a good link about how to persist dynamic controls and their state.
If you want to access your control in PostBack or you want to bind Event, you have to create them in CreateChildControls() method.
private UserControl _uc = null;
/// <summary>
/// Creates all controls.
/// </summary>
/// <remarks>All the controls must be created in this method for the event handler</remarks>
protected override void CreateChildControls()
{
_uc = new UserControl ();
this.Controls.Add(_uc);
base.CreateChildControls();
}
Create your control in Page_Init. Then make it visible on your Button_Click event.
(CTRL+C/CTRL+V from some other question I answered last week):
Everything that has to be maintained between page cycles should be declared in Page_Init, not Page_Load.
All the initialization, like adding event handlers, and adding controls should be added during initialization, as the state is saved between page cycles. Handling with the content of controls and the viewstate, should be done in Load.
Check also http://msdn.microsoft.com/en-us/library/ms178472.aspx.
Init
Raised after all controls have been initialized and any skin
settings have been applied. Use this
event to read or initialize control
properties.
.
Load
The Page calls the OnLoad event method
on the Page, then recursively does the
same for each child control, which
does the same for each of its child
controls until the page and all
controls are loaded.
Use the OnLoad event method to set
properties in controls and establish
database connections.
Two possible approaches:
Have the control in the page but not loaded with anything until they click their button. Then you can populate the values in the control. This has the benefit of being within the page life cycle. Note, you can always use the "display: none" style setting for the that your user control is in. Then, as part of the OnClick for the button, you can reveal the div making your control visible.
You could pop up another window, though obviously this has the potential for being blocked by popup blockers.