My aspx pages pages are drived from a base class, my base class creates the dynamic header of my website. I have a method called "genMenu" and i call in within pageLoad event of base class to create menu.
In some pages i need to override this method, however as we know page load of base class fires before the pageLoad of drived pages. So i cant really do that.
So how can i override the genMenu in aspx page and NoT fire it within base class. I know i can manually call the genMenu function in all drived pages, and not call it within pageLoad of base class, but there has to be a better way of handling it.
Create a virtual method called GenerateMenu or something like that, and always call it from the base page. Do the actual work there. Then your derived pages that need to intercept it can override that instead.
E.g., something like this:
// Base page
protected SomeType MenuVariable;
protected void Page_Load(object sender, EventArgs e)
{
this.GenerateMenu();
}
protected override void OnInit(EventArgs e) {
this.GetMenuVariable();
}
private void GetMenuVariable() {
// Some stuff with query string or the database
this.MenuVariable = FooBar();
}
protected virtual void GenerateMenu() {
// Generate the menu here
}
And:
// Derived page
protected override void GenerateMenu() {
// Calls from the base page Load event
// will be intercepted by this override
// Do the alternate work for this page
// here
}
Updated based on clarification:
In your base class, define a virtual method called AutoCallGenMenu(), which returns true by default. In your page load in the base class, check the result of that method, if it returns true, call genMenu().
In the pages you want to manually call genMenu(), override AutoCallGenMenu() to return false. Then, just manually call the method where you need it.
Instead of pageLoad, why don't you use pageInit or page_init to call your method, so that it occurs before page_load?
Refer to the. Net page life cycle for order of execution, you can then decide which method is best to use
http://msdn.microsoft.com/en-us/library/ms178472(v=vs.100).aspx
I may have misunderstood your question, but tou could also override your genmenu and ignore thr call to .base()
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.
I have a user control (Navigation) nested within another user control (Header) that is dynamically loaded from a Control class (Standard).
The user controls, Navigation and Header have AutoEventWireup = false.
The control class Standard calls loads the Header user control from a configuration item.
private void layoutAndRender(HtmlTextWriter output, string UserControlKey, NameValueCollection UserControlsConfiguration)
{
if(UserControlsConfiguration[UserControlKey] != null && UserControlsConfiguration[UserControlKey].ToString() != "")
{
string suc = System.Web.HttpContext.Current.Request.ApplicationPath + UserControlsConfiguration[UserControlKey].ToString();
UserControl ucToRender = (UserControl)this.Page.LoadControl(suc);
ucToRender.RenderControl(output);
}
}
My problem is that I want to initialize an object in the Navigation user control that can accept Page.Request and Page.Response, but events don't seem to be firing in the Navigation code behind.
The code I'm using to initialize my object is:
this.browser = new Browser(this.Request, this.Response);
I tried doing this during the Navigation constructor but this.Request and this.Response are not set at that time.
I tried using the statement in a void Page_Load(object sender, System.EventArgs e) method, but this doesn't seem to be firing, even if I have this.Load += new System.EventHandler(this.Page_Load); in the Navigation constructor.
I've also tried similar statements for Page_Init and Page_PreRender, but none of these seem to be firing.
Is it that a control loaded with LoadControl does not fire Load or Init events, if loaded the way I have loaded them, and the same goes for any user controls that it may include?
If AutoEventWireup is set to false for the controls that you want to load, then you should override the OnInit method to wire up the Load event handler for the controls. The Request and Response properties should be available from within Page_Load.
For example:
public class Header : Control
{
private void Page_Load(object sender, EventArgs e)
{
}
override protected void OnInit(EventArgs e)
{
this.Load += new System.EventHandler(this.Page_Load);
}
}
See MSDN for more info on AutoEventWireup:
http://support.microsoft.com/kb/324151
Unfortunately, this is legacy code, and not always done the right way.
In particularly, because the user control is loaded and rendered manually, it probably skips most of the event model that I wanted to take advantage of. Ideally, it should have done an AddControl() to the page, rather than rendering the control to a HtmlTextWriter.
My work around is to override the RenderControl method, and initialize the browser property before passing RenderControl up the chain.
I have a dropdown list in User Control
How Can I get selected value of dropdown list of user control in page when user select another item (auto postback is true)?
I tried to store selected value of ddl in a public member from Selected Index Changed event handler. But this handler executes after page load of container page. I need to load data in page based on selected value in ddl of user control.
Thanks
User Control's code
protected void ddlPageSize_SelectedIndexChanged(object sender, EventArgs e)
{
_SelectedPageSize = Convert.ToInt32(ddlPageSize.SelectedValue);
}
int GetSelectedPageSize()
{
return _SelectedPageSize;
}
There are a number of ways to accomplish what you're looking for. The first is simply to re-order your events in the containing page. If you use the PreRender event rather than the PageLoad event, your drop down selection action will be complete and the information will be readily available.
A second method, which probably more extensible, would be to raise a custom event from your usercontrol that your page listens for and handles. Then the action would be taken directly at the point where the information is immediately available. This allows any containing structure (whether it's a page, usercontrol or something similar) to subscribe to the event and handle whatever is needed.
A third method, a little more rigid, would be to have a function in the containing page that is called by the usercontrol once the data is complete. This requires the usercontrol to have knowledge of the specific page type that it will be included in (making it less extensible) so I wouldn't recommend it.
Edit: Here's an idea for implement option #2 with a custom event:
public partial class MyUserControl: UserControl
{
//All of your existing code goes in here somewhere
//Declare an event that describes what happened. This is a delegate
public event EventHandler PageSizeSelected;
//Provide a method that properly raises the event
protected virtual void OnPageSizeSelected(EventArgs e)
{
// Here, you use the "this" so it's your own control. You can also
// customize the EventArgs to pass something you'd like.
if (PageSizeSelected!= null)
PageSizeSelected(this, e);
}
private void ddlPageSize_SelectedIndexChanged(object sender, EventArgs e)
{
_SelectedPageSize = Convert.ToInt32(ddlPageSize.SelectedValue);
OnPageSizeSelected(EventArgs.Empty);
}
}
Then in your page code you would listen for the event. Somewhere in the page load you would add:
myUserControlInstance.PageSizeSelected += MyHandinglingMethod;
And then provide the method that handles the event:
protected void MyHandlingMethod(object sender, EventArgs e)
{
// Do what you need to do here
}
I want to be able to globally grab a reference to the Page object that is currently being requested, so I've added a Global.asax file.
Is there any way to do this? I assume it has something to do with the Application_BeginRequest event.
You can access the current handler (the page) from global.asax, but not from any stage of the request life cycle. I.e. it is not possible in BeginRequest, but it is possible during PreRequestHandlerExecute:
void Application_PreRequestHandlerExecute(object sender, EventArgs e)
{
var page = (Context.Handler as System.Web.UI.Page);
}
Note that page might still be null, if the handler is not a page. Also, I'm not sure your approach is the correct one. Maybe you should explain in more detail what you want to attempt?
Create a class that is a subclass of Page that does what you want and use this subclass as the base type for all you pages.
public class MyPage : Page
{
//... override whatever you want, add functionality, whatever
}
All other pages:
public class Index : MyPage
{
// Automatically get new behaviour
}
You have to use http module to catch the every request for each page on your application and do whatever you want with the request.
var page = HttpContext.Current.Handler as Page
if(page != null) /// do something with page
PreRequestHandlerExecute should be fine for your purposes (if you don't fancy writing your own HttpModule, which is in fact very easy)
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
.Net Changes the element IDs
I have the following problem (I'll explain it simplified because otherwise it would get too complicated/long).
I need to create an ASP.net server control that is inherited from Panel. Simple enough. When the custom control renders, it should dynamically create a Button, associate an event handler to it (which will also be defined inside the server control) and add this button to the rendered control. The click event handler defined inside the server control does some job which for the moment isn't interesting.
I already coded an example and that works fine. In the constructor of the server control I create a new button control, give it an ID, associate an event handler, on the OnInit of the server control I add the button to the Panel controls (remember, my control inherits from Panel) and then everything gets rendered. This looks something like the following:
public class MyCustomControl: Panel
{
private Button myButton;
public MyCustomControl()
{
myButton = new Button();
myButton.ID = "btnTest";
myButton.Click += new EventHandler(btnTest_Click);
}
protected void btnTest_Click(object sender, EventArgs e)
{
//do something...
}
//...
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
this.Controls.AddAt(0, myButton);
}
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
//...
}
protected override void OnPreRender(EventArgs e)
{
base.OnPreRender(e);
}
protected override void Render(HtmlTextWriter output)
{
base.RenderContents(output);
}
}
This works quite fine. The button gets rendered correctly and when I click on it, the appropriate handler inside this customer server control is invoked and executed. Now the problem however starts when I would like to add multiple instances of this server control to my page because all of my generated buttons will have the same id "btnTest" which results in a conflict. So what I tried is to associate a random number to the id of the button, s.t. it end up being "btnTest1235512" or something similar. This solves my problem with the multiple IDs, but results in the problem that my event handler when clicking on the button is no more called correctly. I guess this is due to the problem that my button always gets another id when entering in the constructor and so the appropriate callback (btnTest_Click event handler) isn't found.
Can someone give me a suggestion how I could handle the problem. Is there some way for remembering the ID of the button and re-associating it. As far as I know however this has to happen in the OnInit, where the ViewState isn't yet available. So storing the id in the ViewState wouldn't work.
Any suggestions??
Implementing INamingContainer should fix the problem. You can then keep naming all your buttons btnTest.
This is just a marker interface so you don't have to implement any methods or properties.
Inherit from INamingContainer like:
public class MyCustomControl : Panel, INamingContainer
{
}
This is a marker interface and requires no implementation. I just verified with your code and it solves your problem.
Implementing INamingContainer will do it for you. It will automatically name the buttons with unique ID's. Just a note, if you need to use any of those buttons in any JavaScript, you'll need to use the ClientID property:
function getButton() {
var myButton = document.getElementById('<%=btnTest.ClientID %>');
}