FindControl and Master Pages

Submitted by Robert MacLean on Sun, 08/05/2007 - 19:12
Continuing with my earlier post on enums where I proved people wrong, I decided to prove another MVP wrong. Once again for those who are already in the know they can skip to example 2 below.

FindControl Basics

First off a primer on FindControl taken from the MSDN help: Searches the current naming container for a server control with the specified id parameter. Example: The following example defines a Button1_Click event handler. When invoked, this handler uses the FindControl method to locate a control with an ID property of TextBox2 on the containing page. If the control is found, its parent is determined using the Parent property and the parent control's ID is written to the page. If TextBox2 is not found, "Control Not Found" is written to the page.
  1. private void Button1_Click(object sender, EventArgs MyEventArgs)
  2. {
  3.       // Find control on page.
  4.       Control myControl1 = FindControl("TextBox2");
  5.       if(myControl1!=null)
  6.       {
  7.          // Get control's parent.
  8.          Control myControl2 = myControl1.Parent;
  9.          Response.Write("Parent of the text box is : " + myControl2.ID);
  10.       }
  11.       else
  12.       {
  13.          Response.Write("Control not found");
  14.       }
  15. }

Searching Master Page content using FindControl

You could build a recursive find control method which searches master pages and content pages control internally looping through each control and checking the ID, but then you would need to also build one which takes logic for the offset overloaded version. Sounds like too much work, and I guess MS thought so too since it was never designed this way. Example 2: If you wanted to search the master page for a control you could do the following:
  1. this.Master.FindControl("ControlID")
This will find any control in the master page which happens to have the ID "ControlID". This control can be a sub control of another control. Whats going on here? Well to understand, I downloaded the famous Reflector and searched Microsoft's Framework for this.
  1. protected virtual Control FindControl(string id, int pathOffset)
  2. {
  3.     string str;
  4.     this.EnsureChildControls();
  5.     if (!this.flags[0x80])
  6.     {
  7.         Control namingContainer = this.NamingContainer;
  8.         if (namingContainer != null)
  9.         {
  10.             return namingContainer.FindControl(id, pathOffset);
  11.         }
There is more to it and you can read it here (You'll need Reflector 5 or higher installed for that to work). The important thing to note is the recursion being done there!!! Thus we do not need to worry about it. There is a problem though, this searches the master page only. How do we get to the content page? Example 3: If you wanted to search for a control in the content page. Assuming our Content Place Holder ID is named "Content" you can then put that in FindControl followed by either $ or : and then the control you want to find.
  1. this.Master.FindControl("Content$ControlID")
  1. this.Master.FindControl("Content:ControlID")
There you go, now you can find any control (nested or otherwise) on any content page :)