… because it kept growing and growing. I was determined to finish this off tonight before falling asleep (always dangerous).
Master Pages: Tips, Tricks, and Traps is an article covering all the inconspicuous points of developing and designing with master pages. Everything from URL rebasing, the munging of client side identifiers, using FindControl, nesting, and even tips for cross page posting.
As always, I appreciate any feedback. I’m particularly interested to know if the reader finds the intermingling of Visual Basic and C# samples to be useful, or just a terrible idea.
Now to sleep, perchance to dream...
Comments
One typo (maybe): "We can visualize what the object hierarchies would look like at runtime with the following diagram." Here you mean "at design time", right?
Question.. I have a base class in App_Code that extends the UI.Page class, and so I created a .master page, and on the content page, I changed BOTH the Inherits attribute of the aspx to the new extended base class name, AND the class declaration (class Default3 : MyExtendedPageClass) but I get:
"Make sure that the class defined in this code file matches the 'inherits' attribute, and that it extends the correct base class (e.g. Page or UserControl"
Should I NOT change the class declaration?
and one more while I got you interested... Can you use multiple user controls programatically on a Master page itself? (not the content page) and what is the correct way to do it??
I hope you can help me out. Thanks!! GREAT article BTW
Make sure you also add the CodeFileBaseClass attribute in your @ Page directive and point it to that base class.
Yes, you can programatically use user controls on a master page. I wouldn't treat the master page any different than a regular Page, all of the same examples apply.
Good Article. I've been fumbling with findcontrol and masterpage's for a while. I decided to use the property get set instead, much cleaner. I'm curious though and forgive me if I missed this or if this is a stupid question but is there a way to expose all of the controls properties as opposed to just the specific property, when you call it?
Thanks,
Jon
--
I completely and thourgh;y hate the Name Mangling when using master pages. It makes it damn near impossible... or highly impractical to create sanely named CSS outside of using themes.
This becomes twice as bad when you have developers who do the code, and designers who do the CSS, and you have a predefined Id naming conventions. The Id the designers see in the .aspx source isn't what you get in the output, obviously makeing CSS mistmatch the expectations.
It's why we're not using master pages at all.
I can't think of an easy way to expose all of the controls as properties (without writing all the code, that is). Perhaps some sort of macro or VS add-in could do that by generating code.
Chris:
I understand your problem. I guess it is a trade-off the ASP.NET team made (easier for postback resolution, harder for css and javascript). Perhaps it's something they could provide a workaround for in the future.
Hope this helps,
Scott
Nice, thorough, well thought out.
One of the things I appreciate about your tech writing style is that you just don't say, "this is how you do it..."
You give different examples of how it can be accomplished, and then revisit each scenario and point out the pros and cons of each and expanding on the best direction to go. That style is nothing short of value added!
Many thanks for your continued efforts in contributing to edumacation of us knuckleheads out here! :)
Well even if I can't define the entire control it's still a better solution then working with findcontrol. I was pleased to find out I could issue a Atlas UpdatePanel Update command within the property get set routine to show the new changes, since a have a update panel in my master page. It works like a charm. I agree with Ryan about your tech writting style. Keep up the good work!!!
I have read your great article and i have question for you :) if you can please help me.,
i try to implement you code esp "Master Page To Content Page Interaction"
i have setup as you have described in your web site and i always get "null" value here:
i'm working VS2005:
protected void SendEmailButton_Click(object sender, System.EventArgs e)
{
SendEmailEventArgs eventArgs = new SendEmailEventArgs(this.EmailAddressBox.Text);
if (SendEmail != null) <<always null value
{
SendEmail(this, eventArgs);
}
}
if you want to see the whole page, please let me know and ii can post here or email you whichever is easy for you., hope to hear from you soon.
thanks
Content Page To Master Page Interaction?
thank you
The event will be null until someone subscribes to the event. Typically the page would subscribe to the event (SendEmail += new SendEmailEventHandler(...))
I find it's behavior so annoying I created a simple routine to find any control within any other control. This uses recursion to return the FIRST control matching the supplied name. If the control is not found it simply returns null, instead of raising an exception. Let me know what you think.
public static Control Find(Control C, String ControlName)
{
if (C.ID == ControlName) return C;
foreach (Control c in C.Controls)
{
Control cntrl = Find(c, ControlName);
if (cntrl != null) return cntrl;
}
return null;
}
Thanks!
Quick Question-
Any idea on how to create 'Menu round shaped multiline Tabs'in webforms (Asp.net 2.0) similar to 'Tabcontrol' now available in winforms (.net 2.0).
Any available references?
My Email- atulreddy@yahoo.com
Thanks
Vani
srivanimk@hotmail.com
BaseMaster footer = new BaseMaster();
footer.FooterText = "My Footer"; in the contentpage in Page_PreInit, or page load or in a LinkButton1_Click, bombs.
Any idea what I am missing?
I can access and set other properties in the Base Class, no prob but the setting I lifted from your article that starts with
“protected Label FooterLabel;” fails. Thanks again for a great article I will be working on it for a while.
Ed
Your article is very impressive. I have a question though. My case is as follows:
I use a master page which has 4 main ContentPlaceHolders (header, footer, subNavigagion and Main content)
The content pages (child pages of this Master Page) will, at Page_PreRender event load different user controls into this place holders, based on a selected language (up to 7 different languages) and reading from a global resource file (items.resx, items.fr.resx, etc.).
What happens is that the user controls, such as dropdowns or checkboxes, buttons etc… trigger the autoPostBack event but do not go into the actual Click event. For instance: a dropdown will look like this inside the UserControl:
Protected Sub lstAttributeName_SelectedIndexChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles lstAttributeName.SelectedIndexChanged
End Sub
But at runtime, it goes into the pageLoad event for that UserControl and it NEVER reaches SelectedIndexChanged method.
HOW can I make this dropdown to actually go into this method? I’ve been spinning my wheels on this for a while now.
Please help me if you can.
Much appreciated.
Diego Beltrán
You asked for comments about mixing VB and C#?
I have to say, I found it annoying.
Trevor
Any suggestions? This would be awesome because I could dynamically swap out the MasterPage including the parent of all nested MasterPages.
Thanks,
Tyler
Great article - thanks for taking the time to wrote it. I have a particular problem which I don't seem to be able to solve so I was hoping you could offer some insight.
I have a common baseclass called TemplatePage which I use for all my pages which is derived from System.Web.UI.Page. Each page in my site in turn derives from TemplatePage. How can I reference my MasterPage from the TemplatePage class? I get an error at present which states that the master page doesn't exist. I assume that this is because my base class is in the App_Code directory and so the MasterPage class isn't available.
Any advice would be very appreciated
I tried to read it all in one go, but my brain popped, almost as if I'd been struck.
I vow to return, and bring my friends, rough it up a bit, and send it on its way with no lunch money.
James: You've identified the problem. Because App_Code compiles before any .aspx and .master files the base page class won't see any master page types. You could define a base class for your master page, too, and the base page class could talk to the master through that base class (an interface also works).
We've decided instead to use Web Application Projects instead because of these problems. Thanks again for your help
protected new MyMaster Master
{
get { return (MyMaster)Master; }
}
This had been working great but fails in the nested scenario. I can set the MasterType in the page file but I liked doing this in one spot in the base class for all pages. By the way this caused a nasty stack overflow.
Your discussion of using HttpModules to hook into events from an ASP.Net page was very thorough and well organized. I'm a repeat customer to your blog. Keep up the good work.
Pryia: I'd have to see some code. If you could email me a sample that demonstrates the problem, that would work best.
Thanks,
Priya
Gr8 article!!! I was just trying to figure out a better way of including JS scripts in content pages, your article helped me in figuring that out & understanding the limitations of master pages.
-Vik
I have been racking my brains out on this for days...
I have added a menu control to a master page. The only issue I have is when you click on menu items which have navigateURL assigned (as in site maps) the page changes to the URL specified, and you can not tell which menu item was clicked.
I had no problem with this when I used LinkButtons for navigation (on every page) since I could always access them from various pages and change their color.
Of course, I only care about this behavior at the static menu level only. I am using a dynamic menu based upon the contents of a SQL SiteMap table.
Any help or suggestions would surely be well appreciated.
Thanks.
P.S. Why do I see no examples of anyone trying to manipulate the menu control on a master page?
I am having *major* difficulties using the FindControl to access a Button WebControl. I'm using nested master pages, so I've got the following objects I'm working with:
phMain - the ContentPlaceHolderID on my main Master Page, titled ABSOLUTE_main.master
phAdminContent - the ContentPlaceHolderID on my nested Master Page, titled ABSOLUTE_admin.master
btnAdjust - the Button WebControl that resides on my content page
The issue centers around my nested master pages. I did as you mentioned by calling everything out in a single line of code; I used the following (in C#):
WebControl button = (WebControl)Page.Master.FindControl( "phMain" ).FindControl("phAdminContent").FindControl("btnAdjust");
This throws an unhandled NullPointerException, which is on the button "btnAdjust". The button *does* exist, as this line of code (using the hairy munging naming convention) will, in fact, find my button:
WebControl button = (WebControl)Page.FindControl("ctl00$ctl00$phMain$phAdminContent$btnAdjust");
That works...as ugly as it is, but I cannot work this way. I've got other controls that I need to "Find" on the Page, and this guessing game of what the control will ultimately be named is both maddening and impossible.
I decided to simplify my code for grins (try the ol' outward-in trick) by simply seeing what would return from this statement:
ContentPlaceHolder content = (ContentPlaceHolder)Page.Master.FindControl( "phMain" );
Guess what I get??? A null value! Why would I receive a null value on that line of code??? My expectation was to receive an object that I could dissect and eventually work my way into. A null value isn't acceptable.
I decided to go the other way, thinking that maybe the nested master page resolves first, as you suggest in the article. I did the following, by itself:
ContentPlaceHolder content = (ContentPlaceHolder)Page.Master.FindControl( "phAdminContent" );
Any guesses what value came back?? A null. I'm at a serious loss here. What can possibly be going wrong? I can send you anything you need...I'll send it. :)
HELP! :)
I am in an extremely dire situation here. I cannot continue with my project until I get this worked through. Why did I ever attempt to use Master Pages????
Thank you for the article (it was very informative) but it didn't spend enough time on the perils of nested pages. Or, maybe it did, and I just need to stay away from master pages entirely. :)
J.P.
zurilgenj@saic.com
J.P: That does seem like odd behavior. If you want to send me a sample that compiles and demonstrates the problem and I can probably take a look: scott @ OdeToCode.com.
After contemplating hara-kari (j/k), I continued to poke and prod at this problem. I thought back to something you said ("the page will resolve from the inside out"). My nested page (ABSOLUTE_admin.master) would resolve itself and dump all of its constituent controls into its contentplaceholder, then the main master page (ABSOLUTE_main.master) would resolve, and all of the controls from the nested master page would be dumped into the outer-most master page. THEN, the outer-most master page would dump all of ITS controls into the content page....and away I go.
After thinking about this a bit, I wondered what would return if I tried the following code:
Object obj = Page.Master;
Lo and behold, it was a reference to my nested master page (ABSOLUTE_admin.master). This made sense to me, based on what you said about the resolution timing of all elements.
O.k., so I thought a bit....what happens here:
Object obj = Page.Master.MASTER;
And, as expected, I got a reference to the outer-most master page (ABSOLUTE_main.master).
O.k., so now, with all fingers and toes crossed, I tried the following code and prayed and prayed:
WebControl button = (WebControl)Page.Master.MASTER.FindControl( "phMain" ).FindControl("phAdminContent").FindControl("btnAdjust");
And it worked!!! I think the main thing I have to keep in mind when working with nested master pages is that you ALWAYS have to move to the outer-most level...get a reference to the outer-most ContentPlaceHolder first, then drill into it to get what you need. So, in my case, I needed the master OF THE MASTER to begin my search.
And, it makes total sense...you need to start with the FindControl() method at the page level, then drill into each container to get what you are after. I just need to keep in mind that the ContentPlaceHolders in the Master Page environment are the outer-most containers...always. :)
<insert huge sigh of relief> I sincerely thank you for writing this article, articulating the pitfalls of Master Pages. My Professional ASP.NET 2.0 book from WROX is very well-written, but only introduces you to Master Pages. I was able to get my pages working, but the issues I've been facing have been long and difficult. I believe your article will come in handy down the road to side-step these landmines.
Thanks so much!
J.P.
Great article, and timely too. I will be back. In the article, you mention using a HttpModule to set the Theme for all pages. Couldn't the same be done in the global.asax in the PreRequestHandlerExecute event? This would save having to configure the web.config for the application. Thoughts?
Steve
That's true, it's just I've seen global.asax file grow out of control with little bits of functionality here and there, so proceed with caution :)
Consider this code:
MasterPage 1:
<asp:ContentPlaceHolder ID="cphHead" runat="server">
</asp:ContentPlaceHolder>
Some Html...
<asp:ContentPlaceHolder ID="cphBody1" runat="server">
</asp:ContentPlaceHolder>
MasterPage 2:
<asp:ContentPlaceHolder ID="cphHead" runat="server">
</asp:ContentPlaceHolder>
Some Html...
<asp:ContentPlaceHolder ID="cphBody2" runat="server">
</asp:ContentPlaceHolder>
Page:
<asp:Content ID="Content1" ContentPlaceHolderID="cphHead" runat="Server">
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="cphBody1" runat="Server">
</asp:Content>
<asp:Content ID="Content3" ContentPlaceHolderID="cphBody2" runat="Server">
</asp:Content>
This will issue an error saying that the content is pointing to a cph that doesn't exist (which is a logical error). However, I'm building multibranded sites that will need such an approach!
I tried to find ways to catch the error and ignore it, also, tried, in a HttpModule, to find the Content that doesn't have an equivillent CPH to remove it from the page but that didn't work!
The problem is that you can't catch the Content because it doesn't really exist!
Do you have any solution or an alternative approach (not by using IF ELSE) for this problem?
Regards,
Adam
Best "Get under the hood" Master-Mechanic article on MasterPages on the net. Good work.
Appreciate it!
Your guide touches on sharing masterpages across multiple apps. Your first suggestion seems the most appropriate although I cannot get it to work. Just a "Masters/Master1.master" file does not exist error. I created the virtual directory for the web app using the masterpage app through the IIS admin. Is that what you meant?
Thanks
In the meantime, I would be most grateful if you could answer a question that I posted to a newsgroup by did not receive a satisfactory answer:
groups.google.com/.../eb862a9635f5ad3e
The only solution i could think of was to pass the server rootpath into a javascript variable and then use this in the javascript file...
<script language=JavaScript>
var rootPath = '<%= ResolveClientUrl(".") %>' + '/';
</script>
I added this to the MasterPage.
I have a question for you. I have a master page which takes care of tracking page views etc. I then have a content page which varies based on the query string.
I want to have the code in the master called but cache the page content as neccessary.
I can cache the content of the page in a user control and that is fine. What I can't (yet) do is somehow cache the html header section (ie meta tags for keywords, description, and page title), without caching the WHOLE page.
Right now the first request has the updated header but all subsequent (cached) pages revert to the master page's version of the header.
Do you have any idea how I could fix this?
Thanks
John
thank you very much
Fabiano Arruda
fabiano.arruda@cesar.org.br
i am having one master page and 3 content pages are there.In the content page1 i am giving refernce in the aspx page of remaing 2 pages.Its working fine but "The issue is since each page is compiled to a different assembly it does not know the referes and hence cannot reference it." what the next step i had to proceed?
plz clarify ASAP.
thks
Great article, now I actually understand at least a little bit of masterpages!
Meta tags is the only trouble we've had with Master pages, which was an oversight on Microsoft's part. Anyway, I tried to implement as you've outlined in the article, to no avail. Here are my steps:
1) Create a new Class file in App_Code that inherits from Page (I've called this MetaPage)
2) That class contains your code and seems to compile OK
3) I then changed an individual ASPX codebehind page to inherit from that new MetaPage instead of the usual Page; this seems to match what you have as well since it's in the @Page directive
Anyway, once I add in the "MetaKeywords" in the Page directive, it barfs that it's not an attribute of System.Web.UI.Page, even though I'm inheriting from my MetaPage instead. I did not touch the Master file, as your example also did not seem to touch the Master file. Any guidance is appreciated. :-)
That is the Visual Studio validation being overly zealous.
The project should still compile and run, it's only Visual Studio that complains because it doesn't know about the property.
Let me know,
No, it neither compiled nor ran. Does the .master also have to inherit from the MetaPage class or just the Page class?
Do you have a working sample project that implements this perchance? I have an alternate solution that doesn't do page directives instead using a Page_Load that calls the Master, but my graphics designers don't do/understand code-behind code, but could deal with page directive codes. They are the ones frequently tagging these, so your solution is the most elegant... if it would work.
Thanks! :-)
ARe you using code-beside files (CodeFile="")? If so, use a CodeFileBaseClass attribute also. The CodeFileBaseClass attribute will contain the name of your base class. I'll be posting a sample tonight or tommorow, stay tuned.
I need to find out what page has been loaded as a child of the master page.
Reason, I have a few menus that are on the master page which are in panel containers and I only wish to make certain panels visible depending on which pages are selected.
So, I need to check from the master page what child page is active.
Thanks in advance.
1 js file location itself has to be resolved in sub-folders
2 url of dialog called in a javascript function requirs resolution
(2) can be resolved as follows in code-behind.
if (!Page.ClientScript.IsStartupScriptRegistered("JavascriptSiteNamePrefix"))
Page.ClientScript.RegisterStartupScript(typeof(Page), "JavascriptSiteNamePrefix", @"<script language='javascript'> var rootPath = '" + Request.ApplicationPath + "/'; </script>");
Thanks in advance
Great article. Two quesitons.
1. any thoughts on how to get a background image into a div tag on a master page? (that works from aspx pages in subdirectories).
2. How to you format your code on your blog?
Thanks! -Peter
1) I'd set the background image using CSS and keep the image and style sheet in the theme directory.
2) I use Jeff Atwood's code formatting macro: www.codinghorror.com/blog/archives/000319.html
I'm not quite understanding what you mean by placing the image in the theme directory. I put the jpg in my directory called "MyProject/App_Themes/ThemeNormal" and made my background in the css this:
<div id="header_image" style="background: transparent url(bg_header.jpg) repeat-x scroll 0% 0%;cursor: pointer;">
I'm still not getting the image.
Sorry for being a little thick.
-Peter
A web form with a div like:
<div class="myDiv">
....
</div>
and the web form sets Theme="SomeTheme" in the @ Page directive. Inside of the SomeTheme directory is a .css file with the following:
.myDiv
{
background-image: url('example.jpg');
}
The .jpg file is also inside the themes directory.
This does work for me as the browser will request the .jpg file relative to where it fetches the style sheet from, so even with web forms in different sub directories the path is valid.
Let me know if that works / makes sense. Getting a little fuzzy here late at night.
I have blogged a tidy solution to including javascript files in a consistent manner.
extraview.co.uk/...
thanks for a great article! When implementing the HttpModule i found that my login page crashed. This page is a stand alone page and does not belong to any MasterPage. I resolved it by doing a null check:
Page page = sender as Page;
if ((page != null) && (page.Master != null))
{
...
}
Just thought I should share this...
/Arne (Sweden)
Thanks, it helped.
One note: in Javascript opened windows, the way to address controls on the opener also changes; I didn't figured it out yet though.
Great article!
I have some problems though with my master page.
The master page has a backgroung image and a login.aspx as the startup content page. When i ran the project, the image is not displayed in the startup page (login.aspx) but when login is successful and control is transferred to my default.aspx the image is displayed.
In my web.config the authentication mode="forms". Whenever i change this to "windows" the project works fine. How can i display images in the master page when the "authentication=forms" in web.config ?
Hope you can help me.
Thanks.
Thanks a million!
@Ricky: Check this post by ScottGu: weblogs.asp.net/.../437027.aspx
Great article! The best one on this topic.
I have a question that was not covered in it though. In one of the content pages I have the following (simplified) setup - runat="server" omitted, etc.:
<asp:Content ContentPlaceHolderID="driver">
<asp:TextBox ID="tb">
</asp:Content>
<asp:Content ContentPlaceHolderID="data">
<asp:GridView DataSourceID="ds" />
<asp:ObjectDataSource ...>
<SelectParameters>
<asp:ControlParameter ControlID='<%= GetControlID("data", "tb") %>' .../>
</SelectParameters>
</asp:ObjectDataSource>
</asp:Content>
The problem is that GetControlID method is never called in this scenario and request is failing. Obviously, the ControlID parameter for the ControlParameter control is set before...
I've been banging on this problem for quite some time and couldn't find a solution. Any help would be greatly appreciated. It would be also very interesting to hear your recommendations regarding inter-contentPlaceholder controls interactions.
Thanks again for the superb article!
Michael
I am using a custom control dervied from compositecontrol class. I have a button in this control which fires an event. When I use this custom control in a normal aspx page it works fine, but in master page the event is not getting fired. Could you help?
Error 1 Error parsing attribute 'metakeywords': Type 'System.Web.UI.Page' does not have a public property named 'metakeywords'. c:\inetpub\wwwroot\showMachines2.aspx 1
What can I do to fix this ??
Thanks,
Mario
We put all this time into figuring out how to use something that is supposed to save us time. You have to ask yourself: was it worth it? Perhaps another excellent article called "Master Pages: Use them? or Avoid them?", would be in order to address the type of site it is worth using them on.
Thanks!
ED
I am trying to use the "Define a custom SendEmail event, and let each page subscribe to the event" but having problems to get it to work.
Is it possible to display the entire sample here for downloads?
I have the following code in my Content's page but keep getting this error message "No overload for 'EmailReport' matches delegate 'System.EventHandler'" . Can you please tell me what I am doing wrong? Thanks a lot!
---------------------------------------------
protected void Page_Init(object sender, System.EventArgs e)
{
Master.SendEmail += new System.EventHandler(this.EmailReport);
}
protected void EmailReport(object sender, classLibrary.SendEmailEventArgs e)
{
string address = e.ToAddress;
// do work
}
Meta tags is the only trouble we've had with Master pages. Anyway, I tried to implement as you've outlined in the article, to no avail. Here are my steps:
1) Create a new Class file in App_Code that inherits from Page (I've called this BasePage)
2) That class contains your code and seems to compile OK
3) I then changed the Default.aspx codebehind page to inherit from that new BasePage instead of the usual Page; this seems to match what you have as well since it's in the @Page directive.
Anyway, once I add in the "MetaKeywords" in the Page directive, it barfs that it's not an attribute of System.Web.UI.Page, even though I'm inheriting from my BasePage instead. I did not touch the Master file, as your example also did not seem to touch the Master file.
I tried the CodeFileBaseClass attribute as well but that gave me even more errors.
Any guidance is appreciated. :-)
I've been testing and it would appear so. This means that currently written applications that you plan on 'wiring up' to a Master Page can no longer use server-based forms that get even simple postbacks (i.e. Request["dropdownlist1"];).
In my testing, I did something this simple and it works without master pages, but once connected (and setting the MasterType virtual path), the code no longer retrieves the data.
Thoughts?
So now I would like to push a button on the web user control that is on the first tab and have the second tab appear or become active.
I need a way to access the webtab control from the web user control that is on the first tab.
This may not be a master page problem at all and if not, I appologize. Thank you.
Great article on master pages. We use masterpages in .net 2.0 and also use dreamweaver templates. This is so our customers use macromedia contribute to edit pages. This works great however the customer has the ability to change the title tag within contribute. we have a content control within ht e head to set the title tag. However asp.net always adds an empty title tag on the page as well so we end up with 2 title tags.
Is it possible to turn off the title in the page directive or remove it when the page is rendered?
Thanks
@ Heather: That is not really a master page problem, but I'd look at having the control raise an event to the page, and the page will then change the visibility on the tabs.
@ Bill: You have to be careful with using syntax like Request.Form["xyz"], because names can change. It would be better to access the drop down list through the field.
@ Patrick: I'd need to see some code. I believe you sent me an example in email :)
Very informative article and thanks for that.
I have a question on Sharing the master page with multiple applications.
As you explained in your article, we are implementing with IIS sharing approach. With that approach, I am getting two types of errors
1.When we use MasterType in the aspx page, it added public get property in the corresponding designer file which is by design. But it did not recognize the masterpage type and so the build is failing. Of course the reason was, the application dll can not find the masterpage type. One way to solve this copy the master page project dll into this application bin directory. But whenever we make changes to Masterpages, we need to copy the dll back to application bin direcotry which is big maintenance issue in our case. Did you go through this?
2.Application content page could not find the masterpagefile and so source mode of the page is complaining as "masterpage file not found" Do you think it is VS 2005 issue?
Ram
In some cases I skip the strongly typed MasterPage property. Instead, I define an interface in a class library and reference the class lib from both the master page project and the web site project.
The master page can inherit from the interface and implement its members. The content pages cast the MasterPage property to this interface type and invoke the properties.
<head runat="server">
...
<meta name="author" content="<%= MASTER_COMPANY_NAME %>" />
<meta name="copyright" content="<%= MASTER_COMPANY_NAME %> - <%= CurrentYear %>" />
...
</head>
When a page renders, they look like
<meta name="author" content="<%= MASTER_COMPANY_NAME %>" />
<meta name="copyright" content="<%= MASTER_COMPANY_NAME %> - <%= CurrentYear %>" />
After i read your article i created a master page implemengting the following interface:
public interface IMasterForm
{
string MasterFieldText
{
get;
}
}
after implementing the above interface in masterpage:
-------------------
public partial class MyMaster : System.Web.UI.MasterPage, IMasterForm
{
protected void Page_Load(object sender, EventArgs e)
{
if (ContentPlaceHolder1.TemplateControl.Page.PreviousPage != null)
{
IMasterForm form = ContentPlaceHolder1.TemplateControl.Page.PreviousPage.Master as IMasterForm;
if (form != null)
{
if (!string.IsNullOrEmpty(form.MasterFieldText))
{
//here i will set the label which is supposed to be in all the pages
setLabel = form.MasterFieldText;
}
}
}
}
public string setLabel
{
set
{
lblResult.Text = value;
}
get
{
return lblResult.Text;
}
}
#region IMasterForm Members
public string MasterFieldText
{
get { return setLabel; }
}
#endregion
}
------------------------------
I want to set the master page values only once in page1 and maintain the same master page values for the remaining pages(page2,page3,page4...)
page1.aspx.cs:
public partial class Page1: System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
protected void Button1_Click(object sender, EventArgs e)
{
((MyMaster)Page.Master).setLabel = txtBox.Text;
}
}
page1.aspx:
<%@ Page Language="C#" MasterPageFile="~/MyMaster.master" AutoEventWireup="true" CodeFile="Page1.aspx.cs" Inherits="Page1" Title="Untitled Page" %>
<asp:Content ID="Content1" ContentPlaceHolderID="ContentPlaceHolder1" Runat="Server">
<asp:Label runat=server ID=myLableResult Text="TestTransfer1 Page"></asp:Label>
<asp:Button ID="Button1" runat="server" Text="Button" PostBackUrl="~/Page2.aspx" />
</asp:Content>
---------------
After i implemented this logic i could able to browse through into different pages with postbackurl setting in each page control to a different page.
Is this a good idea or is there any other way to implement? as i don't want to implement the interface in each child web form and carry the values along with the child web pages.
Not sure I follow the question. ScottGu expanded on the nested master tricks here: weblogs.asp.net/.../430382.aspx.
@ Tom: I would probably add those tags using code behind.
@ Sree: I would probably let the master page maintain its state in the database, or in Session. This keeps the content page and master page a bit more seperated.
I am developing an application using ASP.NET.
I have a form and would like to include a form within it.
Any help will be appreciated.
I find myself very frustrated by the difficulties in using javascript libraries with master pages. I don't really understand the methods posted above for javascript inclusion, so I tried one of the methods you suggested, with no success I'm afraid.
I have a questions.aspx page and a questions.js library in the root directory of my web app. The master page is in a master directory ie:
~/master/template1.master.
I can't get VS 2005 to debug javascript written into the aspx page so I have been using included js files for the debugging as well as the efficiency of grouping functionality.
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
I think this should work, but it doesn't....
Dim si As HtmlGenericControl = New HtmlGenericControl()
si.TagName = "script"
si.Attributes("runat") = "server"
si.Attributes.Add("type", "text/javascript")
si.Attributes.Add("src", "~/Questions.js")
Master.Page.Header.Controls.Add(si)
Any ideas or suggestions would be great.
thanks for your time
David
Master Pages cannot access Session?
Myth.
The base master page has 2 user control and i conent placeholder. my problem is the button click event is not getting fired in the page. It's not at all doing post back.
I'm just starting to use master pages and have put all my navigation buttons there. I'm trying to reset them using the following code structure but can't find any buttons. I tried getting hold of the contentplaceholder, but can't loop through it.
protected void Reset_Buttons()
{
foreach(Control ctrl in Page.Master.Controls)
{
if(ctrl is Button)
{
Button btn = (Button)ctrl;
MessageBox.Show(btn.Text);
}
}
}
thanks,
Graham
@Saravana: That is a scenario that should work find. I can't say more without seeing the code.
@Graham: MessageBox won't work on the server. It pops up a windows message box that nobody would be able to see.
Also, the buttons are probably inside a form control. Set trace="true" in your @ Page directive and see what the button's parent control is. Loop through the parent control's Controls collection. Hope that makes sense.
great article, I find it very useful, 10X.
I have request can someone please translate the following VB code to C#
<%@ Master Language="VB" %>
<script runat="server">
Public Event SendEmail As SendEmailEventHandler
Protected Sub SendEmailButton_Click(ByVal sender As Object, _
ByVal e As System.EventArgs)
Dim eventArgs As New SendEmailEventArgs(EmailAddressBox.Text)
RaiseEvent SendEmail(Me, eventArgs)
End Sub
</script>
<script runat="server">
Protected Sub Page_Init(ByVal sender As Object, ByVal e As System.EventArgs)
AddHandler Master.SendEmail, AddressOf EmailReport
End Sub
Protected Sub EmailReport(ByVal sender As Object, ByVal e As SendEmailEventArgs)
Dim address As String = e.ToAddress
' do work
End Sub
</script>
I cannot understand what are the orders:
RaiseEvent SendEmail(Me, eventArgs)
and
AddHandler Master.SendEmail, AddressOf EmailReport
what are the parallel functions in C# that I have to wirte down?
and again 10X
Keren
Thank you very much for such a nice article. I wish I should have read it before submitting my project. But any how I have got a great help I was stuck for running a javascript function and I finally found that I should use ctl00_ContentPlaceHolder1_Label1 in place of label1 in content page. Can you please tell what should be used for master Page Controls?????
“Dynamic Server Controls, Events in content pages that also utilize a MasterPage…”
Basically, for this test I have some dynamic server controls, a dropdown, button and textbox for example…
They are all created in the page_init of the content page as are the event handlers…
Pretty standard stuff, when there is no MasterPage the events are raised as anticipated, when a plain jane MasterPage is added, the dynamic events for said dynamic server controls are not raised…
Can’t seem to make it fly…
Can you shed any light on the subject, possibly a blog article with a functional sample?
Thanks in advance.
I was wondering if someone would help me with an issue that's driving me insane.
I have a menu control that works fine on an aspx page. However, when I move the control to a Master page, it behaves differently.
Specifically, the when you hover over a link in the Menu control, the entire <td> background should change color. When the control is on the Master page, only the background around the actual text changes.
As far as I can tell, the only difference in the resulting HTML is in the class attribute.
e.g,
class="Header1_Menu1_1 TopNavLink Header1_Menu1_3" (when it's on the page)
class="ctl00_Header1_Menu1_1 TopNavLink ctl00_Header1_Menu1_3" (when it's on the Master page)
Anyone know why? My designer won't let this slide by!
Great article!
I’m developing a CMS like application, where I would like to use a MasterPage for the “outer design” and a single Content page, which dynamic builds the “inner content” for the page, loading UserControls and “injecting” these into the Content Page.
What I have is this:
.aspx file
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="mhaDynContent.aspx.cs" Inherits="mhaDynContent" Title="Untitled Page" %>
.aspx.cs file
protected void Page_PreInit(object sender, EventArgs e)
{
this.AppRelativeVirtualPath = "~/mhaDefault.aspx";
this.MasterPageFile = "~/MasterPage.master";
base.AddContentTemplate("ContentPlaceHolder1", new TestContent());
}
public class TestContent : System.Web.UI.ITemplate
{
void System.Web.UI.ITemplate.InstantiateIn(Control container)
{
container.Controls.Add(new LiteralControl("Hello World"));
//Control toAdd = LoadControl("mhaCalendar.ascx");
//container.Controls.Add(toAdd);
//UserControl a = new UserControl();
//a.LoadControl("mhaCalendar.ascx");
//container.Controls.Add(a);
}
}
I can easily add a new control (like e.g. the LiteralControl to the “container”, but what I really would like to do is load (“inject”) a UserControl into the container and I can’t make this work (I’ve commented out some of my code – attempts :)
I hope you understand my problem and any help would be appreciated.
Best regards,
Michael Holm Andersen
Does anyone know how I would take this example below and change it to inherit from the base master page class defined below?
-----------------------------------------------------------------------
File: default.master
-----------------------------------------------------------------------
<%@ Master Language="C#" AutoEventWireup="true" CodeFile="default.master.cs" Inherits="Resources_default" %>
...
-----------------------------------------------------------------------
File: default.master.cs
-----------------------------------------------------------------------
using System.Collections;
...
public partial class Resources_default : System.Web.UI.MasterPage
{
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
Trace.Warn("MADE IT");
}
}
}
-----------------------------------------------------------------------
File: BaseMasterPage.cs (located in App_Code)
-----------------------------------------------------------------------
using System;
...
public abstract class BaseMasterPage : MasterPage
{
//NOTHING HERE YET
}
-----------------------------------------------------------------------
I cannot figure out how to "wire" it up so that my events in the default.master.cs are handled.
I appreciate any suggestions.
Kevin
Any assistance would be great...
Master Page: MasterPage.master
Content Page: detail.aspx
Form View Control: FVDetail
HyperLink Control: mapLink
I have tried many ways but couldnt solve the problem. I will be thankful if somebody can solve my problem
I was wondering to call an event from master page. your article helped me out.
You are doing great job.
Cheers,
Satish Kacham
I want to change a label in my master page. Thanks to your article I have manage to do that.
The problem is that I have to do that in every page, is there a way to optimize that?
Thanks
I am still having a little trouble. I built a Master page, build a separate Header control, added the control to the master page.
Now on other pages, I would like to access and change the label on the Header control.
Is there a way to do this?
-smc
Question:
I want to disable back button effect of browser in my asp.net application.but i want to do it in a particular content page of a master page.
can you please suggest a solution.?
i have a registration flow like 7 to 8 pages....patient inputs data and when it clicks on next updatedataholder() method calls which saves the content of that page and put it in session.
now the complex part i want to implement a breadcrumb thing in master page and i should be able to navigate from 1st to for example 5th page.
Questions is how will i know that what was previous page? and previous page updatedataholder() should be called? the worst approach is i call this method on every page unload event? what do you say?
Thank u in advance.
i have master page name :sitemaster.master
page:default2.aspx
page:default3.aspx
control on master :treeview
on form load of Default2.aspx i am changing the label1.text of masterpage.But when i used to go to default3.aspx using tree view then the label1.text of master page is showing empty.
how i can show same text of label1 in default3.aspx also.
If cak give some ideas it will be great help.
thanks and regards,
lokesh
I just want to give you some feedback on the section that you called Name Mangling.
You mention in this section taht for being able to get back information from a javascript block to use it in some field it was necessary to do the next:
Dim script As String = "[Label1ID].innerHTML = 'boo!';"
Dim scriptKey As String = "SayBoo"
Dim addScriptTags As Boolean = True
Protected Sub Page_Load(ByVal sender As Object, _
ByVal e As EventArgs)
script = script.Replace("[Label1ID]", Label1.ClientID)
ClientScript.RegisterStartupScript( _
Me.GetType(), scriptKey, script, addScriptTags _
)
End Sub
Unfortunlly when you are behind an Ajax UpdatePanel this do not work.
I found some way to fix this issue.
You have to set the next code:
document.getElementById(myFieldID).innerHTML = 'Something'
NOTE: myFiledID is send it from the codebihinf of the asp.net page of this way:
javascriptfucntion('" & txtNombreCliente.ClientID & "')
And this is it. I hope ths be usefull for the people that use to read your article.
Regards!
Juan Fco Ochoa
Mexico(country),Coahuila(state)Saltillo(city)
I just want to give you some feedback on the section that you called Name Mangling.
You mention in this section taht for being able to get back information from a javascript block to use it in some field it was necessary to do the next:
Dim script As String = "[Label1ID].innerHTML = 'boo!';"
Dim scriptKey As String = "SayBoo"
Dim addScriptTags As Boolean = True
Protected Sub Page_Load(ByVal sender As Object, _
ByVal e As EventArgs)
script = script.Replace("[Label1ID]", Label1.ClientID)
ClientScript.RegisterStartupScript( _
Me.GetType(), scriptKey, script, addScriptTags _
)
End Sub
Unfortunlly when you are behind an Ajax UpdatePanel this do not work.
I found some way to fix this issue.
You have to set the next code:
document.getElementById(myFieldID).innerHTML = 'Something'
NOTE: myFiledID is send it from the codebihinf of the asp.net page of this way:
javascriptfucntion('" & txtNombreCliente.ClientID & "')
And this is it. I hope ths be usefull for the people that use to read your article.
Regards!
Juan Fco Ochoa
Mexico(country),Coahuila(state)Saltillo(city)
So i want that at runtime grid should be visible on whole page and on selecting grid column panel should be visible. But currently at page load my grid is visble on half page and half remain vacant.
so please can u help me i will be very thankful to u
Great article about master pages. I did as you instructed. I added a MasterPageModule class, BasePage class, updated the Webconfig the MyMasterPageModule in httpModules.
When I compiled the code I received the following errorss in my BasePAge Class
Error 1 'BasePage' does not contain a definition for 'PreInit' and no extension method 'PreInit' accepting a first argument of type 'BasePage' could be found (are you missing a using directive or an assembly reference?) C:\Users\sstacel\Documents\Visual Studio 2008\WebSites\WAP_Web4\App_Code\BasePage.cs 20 14 C:\...\WAP_Web4\
Error 2 The name 'MasterPageFile' does not exist in the current context C:\Users\sstacel\Documents\Visual Studio 2008\WebSites\WAP_Web4\App_Code\BasePage.cs 25 9 C:\...\WAP_Web4\
I am not sure what I did wrong. Can you help me resolve it.
Thanks
I HAVE A WEBSITE WITH A MASTERPAGE AND 2 LINK IN MASTERPAGE AND A DEFAULT.ASPX THAT USEING MASTERPAGE FOR CONTENT.
WHEN I CLICK ON THE LINKS WHOLE MASTERPAGE REFRESHING BUT I WANT JUST CONTENT PART REFRESHING WOULD YOU HELP ME?
BEST REGARDS
You are really superb ....
You have given nice information. I am trying to use controls of the content page in the Javascript of the master page. I am not sure is there any way like to use it directly like ctl000_contentplaceholder_contentctlname which didnt work for me. But my problem is in my master page I don't have BODY tag because it is in content pages and Index page. So in Codebehind of Master page I am getting value of the control of the content page and can assign in the Hiddenfield. But then i can not use that field in the javascript of the master page.
Any help will be appreciated.
Thanks,
Deepa
I have some dropdown lists (company,region,country etc..)which are used in different web forms. I have a master page too..Now i wanna create a reusable web control for all dropdowns (which should be part of the presentation layer).
And i tried like this- i created one ascx file with a dropdownlist which binds all regions[Region name] from database. And i added ddlRegion.Items.Insert(0,"--Select--"); in Databind().In a new aspx file with a button the control it works fine.ie.When nothing is selected (--Select--) it will alert as 'Select a Region',and if data is selected it will return the correct selectedValue. Now, my problem is that the javascript alert is not working when i use the control with the aspx page where i have used master page reference[i wrote it in ascx page].Or how can get the first item ie.--Select-- from ascx to aspx???
Just help me out from this...
Am using visual studio 2010-C#,sql server 2008
isn't finding the right control ID when used in a master page - the
master page changes the control IDs on the client.
My aspx page look like this:
<%@ Page Language="C#" MasterPageFile="~/MasterPage.master" AutoEventWireup="true" CodeFile="Company.aspx.cs" Inherits="Basicdata_Company" %>
<%@ Register assembly="AjaxControlToolkit" namespace="AjaxControlToolkit" tagprefix="cc1" %>
<%@ Register TagPrefix="Dropdown" TagName="Region" Src="~/Usercontrol/Dropdown.ascx"%>
<asp:Content ID="Content1" ContentPlaceHolderID="head" Runat="Server">
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="ContentPlaceHolder1" Runat="Server">
<script type="text/javascript">
function validate() {
var objname = document.getElementById("<%=txtCompanyname.ClientID %>")
if (objname.value == "") {
alert("Value is required");
objname.focus();
return false;
}
var objurl = document.getElementById("<%=txtUrl.ClientID %>")
if (objurl.value == "") {
alert("Value is required");
objurl.focus();
return false;
}
/// I tried this type code for ddlRegion[user control] but it returns error ////
</script>
<asp:UpdatePanel ID="UpdatePanel1" runat="server">
<ContentTemplate>
---Something--
<Dropdown:Region ID="ddlRegion" runat="server" Width="128px"
SelectedValue='<%# Bind("SelectedValue")%>' >
</Dropdown:Region>
--Something--
</ContentTemplate>
</asp:UpdatePanel>
</asp:Content>
And this is my ascx:
<%@ Control Language="C#" AutoEventWireup="true" CodeFile="Dropdown.ascx.cs" Inherits="Usercontrol_Dropdown" %>
<script type="text/javascript">
function validate() {
var itoken = document.getElementById('<%=ddlRegion.ClientID%>').options[document.getElementById('<%=ddlRegion.ClientID%>').selectedIndex].value;
if (itoken == "--Select--") {
alert("Select a Region");
return false;
}
}
/// is there any way to pass value of itoken to aspx and make use of that??? ///
</script>
<asp:DropDownList ID="ddlRegion" runat="server">
</asp:DropDownList>
The javascript written in ascx works fine when i make use of it with an aspx which have no reference to master page. What u said is correct-because when i tried to use that id(ddlRegion),it returns error.....ie. object is undefined or null.
Please make me clear with these concepts..
Any solution???
Excellent article...
Finally i got the solution...
Thanks.........
can u help me in showing a user friendly message while throwing exceptions--I am using exception handling application block--how can i do that using replace handler??
I have used,
exceptionMessage="An error has occured, contact admin". Can i have this in an alert box. Am using web application C#, .net 4.0
If possible plz help me out......