Watch Out When Setting the ID of a Master Page Dynamically

It's not uncommon to set the ID of a Master Page in ASP.NET Programmatically. This is particularly useful when you have multiple master pages and want to have your CSS or JavaScript target specific control IDs in your code.

Without setting the ID property of the master page, a client side control ID may end up like this:

<input type="submit" name="ctl00$ContentPlaceHolder1$Button1" value="Button" 
id="ctl00_ContentPlaceHolder1_Button1" /> 

The ctl00 prefix on the id and name attributes represent the auto generated ID of the master page. Even if your page uses a different master, you may end up with the same prefix. Setting the server side ID of the master programmatically allows you to control the full control ID, making IDs predictable and thus more useable in client side code. For example, the following code in the code behind of the master page:

protected void Page_Init(object sender, EventArgs e)
  this.ID = "Master1";
will result in the following HTML for the same button control:
<input type="submit" name="Master1$ContentPlaceHolder1$Button1" value="Button" 
id="Master1_ContentPlaceHolder1_Button1" /> 

This way you can assign a predictable master ID that your client side CSS and script can use.

If you use this trick, you have to be aware of when exactly to set the ID. Do it too late and you'll get in troubles.

In my latest book Beginning ASP.NET 3.5 in C# and VB.NET I made the mistake to recommend setting the ID in Page_Load (on page 276), like this:

protected void Page_Load(object sender, EventArgs e)
  this.ID = "Master";

While this code runs fine in simple scenario's where all you need to do is change the client ID, it will present major problems when you're in a more dynamic scenario, for example when editing data with a GridView or ListView control. When you set the ID in Page_Load and then try to delete an item in a ListView (as is discussed on page 451 and onwards) you may get the following error:

Could not find a row that matches the given keys in the original values stored 
in ViewState.  Ensure that the 'keys' dictionary contains unique key values 
that correspond to a row returned from the previous Select operation.

This error in the PlanetWrox project caused by the master's ID was reported by Gerard Torres in a post on the Wrox forum. He tried out the ID setting in his own PlanetWrox project with the aforementioned error as the result. At first this error may put you on the wrong track (it did to me), leading you to think there's a problem with the keys, like the DataKeyNames attribute on the ListView or with the primary keys in the database. However, it turns out that the keys are stored in ViewState correctly, but with a non matching name. On PostBack, when the key values need to be extracted from ViewState, there is a mismatch between the values stored in ViewState (prefixed with Master1) and the recreated control into which the data is loaded (which is still prefixed with ctl00 because the Master1 prefix has not been set yet).

So always make sure you set the ID in Page_Init, and not in Page_Load. Also, don't try to set the ID in Page_PreInit. Although the Page class has a PreInit event, the master page doesn't.

Finally, try to avoid relying on fixed control IDs altogether. It makes your application more fragile, as changing master pages or your control hierarchy can seriously screw up your client IDs. Instead, use the ClientID and the UniqueID properties that each control has. These controls give you the client side IDs of the controls at run-time, so they are always up-to-date.

Where to Next?

Wonder where to go next? You can post a comment on this article.

Doc ID 469
Full URL
Short cut
Written by Imar Spaanjaars
Date Posted 09/07/2008 13:11


Talk Back! Comment on Imar.Spaanjaars.Com

I am interested in what you have to say about this article. Feel free to post any comments, remarks or questions you may have about this article. The Talk Back feature is not meant for technical questions that are not directly related to this article. So, a post like "Hey, can you tell me how I can upload files to a MySQL database in PHP?" is likely to be removed. Also spam and unrealistic job offers will be deleted immediately.

When you post a comment, you have to provide your name and the comment. Your e-mail address is optional and you only need to provide it if you want me to contact you. It will not be displayed along with your comment. I got sick and tired of the comment spam I was receiving, so I have protected this page with a simple calculation exercise. This means that if you want to leave a comment, you'll need to complete the calculation before you hit the Post Comment button.

If you want to object to a comment made by another visitor, be sure to contact me and I'll look into it ASAP. Don't forget to mention the page link, or the Doc ID of the document.

(Plain text only; no HTML or code that looks like HTML or XML. In other words, don't use < and >. Also no links allowed.