public partial class MasterPage : System.Web.UI.MasterPage
{
protected void Page_Load(object sender, EventArgs e)
{
if(System.Web.HttpContext.Current.User.Identity.Name != "") //if (!Page.IsPostBack)
{
BusinessLayer.ShoppingCart cart = new BusinessLayer.ShoppingCart();
int count = cart.getNoOfProducts(System.Web.HttpContext.Current.User.Identity.Name);
Label lblCart = (Label)Master.FindControl("lblCartNo");
lblCart.Text = " (" + count + ")";
}
}
}
I placed a breakpoint and this code is never called (even without the if statement), also I was not able to find the label which is located in the master page
In order for Page_Load to be called, make sure that in your MasterPage.aspx have AutoEventWireup="true":
<%# Master Language="C#" AutoEventWireup="true" CodeBehind="Site.master.cs" Inherits="Mysite.Website.Templates.MasterPages.Site" %>
Make sure that MasterPage.aspx Inherits attribute matches your code-behind namespace and class name, as well as your .designer.cs namespace and class.
If the aspx and code-behind files all are wired up correctly, then you should be able to remove the FindControl statement.
The Page_Load event for your master page should definitely be firing. Not sure why your breakpoint isn't being hit, but to double check, I'd recommend trying something a bit more brute force to make absolutely sure that the method is definitely not being called:
protected void Page_Load(object sender, EventArgs e)
{
Response.Write("Page_Load");
Response.End();
}
Your label may not be found due to the way controls are nested as Master.FindControl won't work if the control resides inside another control. I'd recommend checking out "Finding controls inside of nested master pages" which has a useful helper method that can be used to search for controls recursively.
Related
I have an authentication roles-based system: different roles are redirected to different folders and in each folder there is a web.config that allows the access only to a particular username.
Few roles have the default page in common with a gridview that react in different ways depending on the role(different columns are shown, events trigger different methods, etc.).
so my problem is that everytime I need to make minor changes to a page I need to copy/paste the same changes to all the others default pages in the other folders.
In terms of code I solved by creating a DefaultFather class which extends System.Web.UI.Page and every other Default class inherits from DefaultFather. In this way, if I dont declare a Page-life-method, the DefaultFather method will be triggered.
but what about the graphic part(html, javascript, asp components, etc...)??
I created a NestedMasterPage just for the Default pages but everytime I need to change the appearance/behaviour of controls(gridview, buttons, linkbuttons) I must use the FindControl() method.
there isnt really another way to solve this problem?
Im thinking of using the Page_Load() method to search for each control with FindControl() and save them into attributes for later usage but it doesnt really look like a good solution.
It would be nice if I could use the masterpage components as properties but I think that in order to do that I should create public properties and I dont know if it will cause some kind of security problem.
any suggestion?
btw, if masterpage is the solution, should I remove the DefaultFather class and place the code directly into the masterpage? or is it a good idea to have another class just for the code?
I'd say there's nothing wrong with having both a master page and a base class for your page. They serve different purposes. The master page is generally all about layout, and the base class would be about page functionality.
If you want to manipulate the markup on your master page, rather than accessing the fields directly, I'd say create a logical function which does what you need it to do, and let the master page do it.
// Site.Master.cs
public void HideSubmitButton()
{
btnSubmit.Visible = false;
}
// Default.aspx.cs
protected void Page_Load(object sender, EventArgs e)
{
((SiteMaster)Master).HideSubmitButton();
}
I'd probably wrap that cast so you can use it more easily - that is something that would belong in your base class:
// DefaultFather.cs
protected new SiteMaster Master { get { return (SiteMaster)base.Master; } }
// Default.aspx.cs
Master.HideSubmitButton();
EDIT
Per your comment about attaching event handlers - if you need to attach events to objects that live on the master (which may not be a good idea - ideally the event handler for something living on the master lives on the master - but if you really need it) you can expose methods to do that as well, like:
// Site.Master.cs
public void AttachEventHandlerToGoButton(EventHandler eventHandler)
{
btnGo.Click += eventHandler;
}
// Default.aspx.cs
Master.AttachEventHandlerToGoButton(DoMyThing);
private void DoMyThing(object sender, EventArgs e) { }
or if you want to get fancy, write a wrapper event:
// Site.Master
<asp:Button ID="btnGo" runat="server" OnClick="btnGo_Click" />
// Site.Master.cs
public event EventHandler GoButtonClick;
protected void btnGo_Click(object sender, EventArgs e) {
if (GoButtonClick != null) {
GoButtonClick(sender, e);
}
}
// Default.aspx.cs
Master.GoButtonClick += DoMyThing;
private void DoMyThing(object sender, EventArgs e) { }
Also see my edit on the Master wrapper - you need the base. there to avoid a stack overflow.
My UserControl code is below, I have one TextBox in UserControl and would like to access TextBox.Text property from web page.
UcUserForm user control is inserted in myform.aspx web page.
On myform.aspx PageLoad I set value for textBox like this
ucUserForm.TbFirstName.Text = "Tomas";
Everything works fine. When web page is loaded I see name inside textbox. Then I change value from Tomas to Jonas.
On myform.aspx ButtonClick I am trying to read value
var mynewname = ucUserForm.TbFirstName.Text;
despite that name is changed from Tomas to Jonas in TextBox on web page I still get the old name Tomas. Can't understand where is the problem.
UserControl code behind
public partial class UcUserForm: System.Web.UI.UserControl
{
public TextBox TbFirstName
{
get { return tbFirstName; }
}
}
UserControl web page
<asp:TextBox ID="tbFirstName" autocomplete="off" MaxLength="25" runat="server"></asp:TextBox>
Registration user control code in default.aspx
<%# Register Src="ucUserForm.ascx" TagName="ucUserForm" TagPrefix="uc1" %>
<uc1:ucUserForm ID="ucUserForm" runat="server" />
Try this:
protected void Page_Load(object sender, EventArgs e)
{
if (!this.IsPostBack)
{
ucUserForm.TbFirstName.Text = "Tomas";
}
}
You set it every time you load the page. Try in Init stage.
Similar to this
protected void Page_Init(object sender, EventArgs e)
{
ucUserForm.TbFirstName.Text = "Tomas";
}
The Init just happens once in the Page's life cycle
http://msdn.microsoft.com/en-us/library/ms178472.aspx
For a "dashboard" module I need to dynamically load user controls based on criteria as the user enters the page (role, etc). The problem is that the events are not being fired at all from the controls
As I understand it I need to load the controls in the OnPreInit method of the dashboard page, however I cannot get a reference to the Placeholder control at this point of initialization (i.e. I get a NullReferenceException); trying to load the Placeholder dynamically via Page.FindControl gives me, ironically, a StackOverflowException.
I've tried loading the controls in PreRender and OnInit as well but the events in the controls are not wired up properly and will not fire.
The code is basically this:
// this does not work; if I try to access the placeholder control itself
// ("phDashboardControls") I get a NullReferenceException, if I try
// Page.FindControl("phDashboardControls") I get a StackOverflowException
protected override void OnPreInit(EventArgs e)
{
base.OnPreInit(e);
Control ph = Page.FindControl("phDashBoardControls"); // Placeholder
if (ph != null)
{
// GetControlsToLoad just instantiates the controls and returns
// an IList<Control>. Eventually it will have logic to
// determine which control needs to be loaded based on user role etc.
foreach (Control control in GetControlsToLoad())
{
ph.Controls.Add(control);
}
}
}
// IModularControl is a custom interface defining a single
// Initialize method to set up a control...
private void Page_Load(object sender, EventArgs e)
{
foreach (Control control in this.phDashboardControls.Controls)
{
if (control is IModularControl)
((IModularControl)control).Initialize(this.CompanyID);
}
}
I've successfully loaded controls dynamically in Page_Load before. The only thing I found I had to be careful of was to ensure that if I did a postback, the same controls were loaded in subsequent page_load to ensure that the view state didn't get corrupted... all events etc worked as expected. In my case the controls flow ended up something like this:
page_load - load control a
(do something which causes postback and event x to fire)
page_load - make sure you load control a
event_x - clear control a, load control b
(do something which causes postback)
page_load - make sure you load control b
...
it meant loading controls you fully intented discarding, but was the only way I could find to not corrupt the viewstate...
If you have a page with PlaceHolder1 and Label1 in it, then the following code causes the button click event to fire just fine:
protected void Page_Load(object sender, EventArgs e)
{
var dynamicButton = new Button() { Text = "Click me" };
dynamicButton.Click +=new EventHandler(dynamicButton_Click);
PlaceHolder1.Controls.Add(dynamicButton);
}
void dynamicButton_Click(object sender, EventArgs e)
{
Label1.Text = "Clicked button";
}
Behaves the same with a user control:
WebUserControl ascx:
<%# Control Language="C#" AutoEventWireup="true" CodeFile="WebUserControl.ascx.cs" Inherits="WebUserControl" %>
<asp:Label ID="Label1" runat="server" Text="Label"></asp:Label>
<asp:Button ID="Button1" runat="server" Text="Click Me" onclick="Button1_Click" />
WebUserControl code behind:
protected void Button1_Click(object sender, EventArgs e)
{
Label1.Text = "Clicked Button";
}
parent control that loads the child control:
protected void Page_Load(object sender, EventArgs e)
{
var dynamicControl = Page.LoadControl("~/WebUserControl.ascx");
PlaceHolder1.Controls.Add(dynamicControl);
}
Just FYI the issue had to do with validation; the events weren't firing properly because some of the validation controls (there were a ton) weren't configured to only apply to that control.
Where is the best part of asp.net page or code behind to register RegisterClientScriptBlock.
You have a bunch of options.
Register script includes in your <head> section or do inline <script> tags. I prefer to have my scripts at the bottom of the page though.
You can also register it at the Page level in your Page_Load (or any other event) by calling ClientScript.RegisterClientScriptBlock and passing it the script you want. Remember that if you do go with RegisterClientScriptBlock, you will need to make sure that you register the code with every page load so that is why I would recommend the Page_Load event if you want to use this method.
For example:
protected void Page_Load(object sender, EventArgs e)
{
AddClientSideJavascript();
// Do other stuff
}
private void AddClientSideJavascript()
{
// Register some client script code
Type someType = this.GetType();
if (!ClientScript.IsClientScriptBlockRegistered(someType, "TESTSCRIPT"))
{
string script = "function ShowAlert() { alert('Test'); }";
ClientScript.RegisterClientScriptBlock(someType, "TESTSCRIPT", script, true);
}
// Register more here... etc...
}
Just make sure you don't include it the portion of your Page_Load that is wrapped with the if (!IsPostBack) check or else your scripts will not get registered after any postbacks.
The correct answer is - at any point within page_load.
I'd like to use an UpdatePanel in my UserControl. The problem is the .aspx page the control is dropped on will NOT have a ScriptManager. I will need to create the ScriptManager in the UserControl. However if the UserControl is used, say twice on the page, then placing a ScriptManager won't work because you can only initialize ScriptManager once.
In other UserControls where I needed ScriptManager (I was using AJAX Toolkit Extensions) I was able to use this code:
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
Page.Init += new EventHandler(Page_Init);
}
void Page_Init(object sender, EventArgs e)
{
if (Page.Form != null && ScriptManager.GetCurrent(Page) == null)
Page.Form.Controls.AddAt(0, new ScriptManager());
}
..worked great, but not for the UpdatePanel case.
Note, I am NOT using Master Pages
(Another approach I was thinking of, but can't figure out how to do, is to programmatically create the UserControl inside an UpdatePanel.)
I do not think this is possible. I have tried it several different ways. You might have to bite the bullet and put a scriptmanager in your page.
What is the reason it doesn't work? Are you getting an exception from the UpdatePanel that a ScriptManager is required? Are you using System.Web.Extensions 1.0 or 3.5? I say that because a change was made to UpdatePanel in 3.5 that causes its content template to instantiate prior to OnInit, so I don't see an obvious reason why that wouldn't work. If there is an exception it would be helpful to see the stack trace.
I am hitting this same problem. The problem is that you need to add the scriptmanager before the OnInit stage - as far as I can see it needs to be done at the preinit stage. You can see this by adding a load of overrides - I found the the page got through the preinit ok, then went to the addedcontrol event and it was at (or just after, but this point makes sense) that the "You need a scriptmanager" gets thrown. I am struggling to find how to add an event handler to the Page.PreInit event from a child usercontrol as the WUCs don't have a PreInit event. Even the WUC constructor doesn't fire before that point and in the constructor the page object is null so you can't add it there. Even at the AddedControl stage of the WUC, you still don't seem to be able to access the main page ( ScriptManager oSCM = ScriptManager.GetCurrent(Page); returns null) so you can't seem to add the scriptmanager, if you need to, before the error is thrown.
/edit:-
As far as I can see it (and I've had no answer to this on the asp.net forums - surprise, surprise) the WUC doesn't start kicking in it's methods/events until after the parent's preinit stage, so there's 2 ways of doing this.
1) The way I think I would do this is to not put any content in the designer that requires the scriptmanager and to put placeholders where such content needs to go. Then in the wuc load you use the ScriptManager.GetCurrent to see if there's one already there and then create it if not. Then you dynamically add the content that requires the SCM. Something like this:-
<%# Control Language="C#" AutoEventWireup="true" CodeFile="wucTestExample.ascx.cs" Inherits="wucTestExample" %>
<asp:PlaceHolder ID="plcAJAX" runat="server" />
<asp:Label ID="lblGeneral" runat="server" Text="This is another label" />
----------------code behind---------------------------
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
public partial class wucTestExample : System.Web.UI.UserControl
{
protected void Page_Load(object sender, EventArgs e)
{
ScriptManager oSCM = ScriptManager.GetCurrent(this.Page);
if (oSCM == null)
{
oSCM = new ScriptManager();
oSCM.ID = "scmAJAX";
oSCM.EnablePartialRendering = true;
this.plcAJAX.Controls.AddAt(0, oSCM);
}
UpdatePanel udpMain = new UpdatePanel();
udpMain.ID = "udpMain";
TextBox txtMain = new TextBox();
txtMain.ID = "txtMain";
// other attrbutes here
Button btnPostback = new Button();
btnPostback.ID = "btnPostback";
btnPostback.Click += new EventHandler(btnPostback_Click);
btnPostback.Text = "Partial Postback";
Label lblPostback = new Label();
lblPostback.ID = "lblPostback";
lblPostback.Text = "initial postback";
udpMain.ContentTemplateContainer.Controls.Add(txtMain);
udpMain.ContentTemplateContainer.Controls.Add(btnPostback);
udpMain.ContentTemplateContainer.Controls.Add(lblPostback);
this.plcAJAX.Controls.Add(udpMain);
}
void btnPostback_Click(object sender, EventArgs e)
{
// implement button code here
Label lblPostback = (Label)this.plcAJAX.FindControl("lblPostback");
if (lblPostback != null)
{
lblPostback.Text = String.Format("WUC POstback at : {0}", DateTime.Now.ToLongTimeString());
}
}
}
then use it thus:-
<%# Page Title="" Language="C#" MasterPageFile="~/MasterPage.master" AutoEventWireup="true" CodeFile="TestExampleNoSCM.aspx.cs" Inherits="TestExampleNoSCM" %>
<%# Register Src="~/wucTestExample.ascx" TagName="wucTestExample" TagPrefix="ucTE" %>
<asp:Content ID="Content1" ContentPlaceHolderID="head" Runat="Server">
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="ContentPlaceHolder1" Runat="Server">
<%--<asp:ScriptManager ID="scmAJAX" runat="server" />--%>
<asp:Label ID="lblLoadTime" runat="server" />
<ucTE:wucTestExample ID="wucTestExample" runat="server" />
</asp:Content>
----------------code behind---------------------------
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
public partial class TestExampleNoSCM : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
this.lblLoadTime.Text = String.Format("Page load at: {0}",DateTime.Now.ToLongTimeString());
}
}
So if you comment or uncomment the SCM in the parent page, the WUC still works either way.
2) I've seen another option where an update panel was needed and the programmer created all the controls in the designer and then looped round them in the page load (after creating the SCM, if needed, and the UDP and added all the controls on the WUC UDP, before then adding that to to placeholder, but this strikes me as rather dangerous as it seems to be double-instantiating control, and I think it may come back to bite them on the bum...
The downside with method 1 is that it's more work to create everything in your updatepanel programmatically, but if you really want to build a self-dependent WUC, that seems to be your price (and hopefully, the WUC shouldn't be that complicated, anyway). Personally, I think in my app (as the WUC won't be used outside it) I'll just make sure I add in an SCM where needed on the main page.
One other, final, note I would pitch in - I've seen people saying "add it to the master page" - this seems to be a particularly bad idea, IMHO, unless every page in your app needs the SCM as it will add a whole new level of bloat to your pages, and that doesn't seem to be a good idea as ASP.NET seems to have a good level of bloat already...
Instead of dynamically adding a ScriptManager if none exists on the page, simply do the opposite: add a ScriptManager to your ASCX and get rid of it if there's one already on the page. So...
protected override void OnInit(EventArgs e) {
base.OnInit(e);
AdjustScriptManager();
}
private void AdjustScriptManager() {
if (ScriptManager.GetCurrent(Page) != null) {
ScriptManager1 = null;
}
}
UPDATE:
Nah, after further testing this won't work, as ScriptManager1 = null does nothing helpful. If there is a way to do this (or to remove the Page control), please comment.
Solution: you can add a scriptmanager dynamically in the usercontrol by checking if the current page does not already contain a ScriptManager. Here's how:)
In the UserControl (ascx) html put this:
<asp:PlaceHolder ID="pHolder" runat="server" />
And in the code behind (ascx.cs):
//insert Scriptmanager dynamically only IF it does not already exist
private void createScriptManager(System.EventArgs e)
{
// the GetCurrent() method will return a ScriptManager from the Page
if (System.Web.UI.AjaxScriptManager.GetCurrent(this.Page) == null)
{
System.Web.UI.AjaxScriptManager manager = new System.Web.UI.AjaxScriptManager();
manager.EnablePartialRendering = true;
pHolder.Controls.Add(manager);
}
}
// call the above method from the usercontrol's OnInit
override protected void OnInit(EventArgs e)
{
//
// CODEGEN: This call is required by the ASP.NET Web Form Designer.
//
createScriptManager(e);
base.OnInit(e);
}
Sometimes it is necessary to define a ScriptManager dynamically. In my case I am using a usercontrol that will be put into different pages, but some of these pages already contain a ScriptManager and some dont, so how will my usercontrol know if it should define its own ScriptManager? The beauty of the above code is that the usercontrol adds a scriptmanager only if there isn't already one on the page.
Note: the System.Web.UI.AjaxScriptManager may be replaced with System.Web.UI.ScriptManager if you use an older version of Ajax.