views:

84

answers:

1

I'm looking for a way to dynamically load a master page in order to get a collection of ContentPlaceHolders within.

I would prefer not to have to load a page object to assign the master page to before I can access it's controls, but if that's the only way I'll be happy to use it. This is the way I was hoping it would work:

        Page page = new Page();
        page.MasterPageFile = "~/home.master";
        foreach (Control control in page.Master.Controls)
        {
            if (control.GetType() == typeof(ContentPlaceHolder))
            {
                // add placeholder id to collection
            }
        }

But page.Master throws a null reference exception. It only seems to load at some point when an actual page has been created in the page lifecycle.

I even thought of dynamically changing the current page's MasterPageFile on Page_Init(), reading all ContentPlaceHolders then assigning the original MasterPageFile back, but that would be horrible!

Is there a way to load a master page into memory independent of an actual page so that I can access properties of it?

My final resort will probably involve parsing the master page contents for ContentPlaceHolders instead, which isn't as elegant but might be a bit faster.

Anyone able to help please? Many thanks.

A: 

You should be able to use LoadControl to load the master page an enumerate the Controls collection.

  var site1Master = LoadControl("Site1.Master");

To find the Content Controls you will need to recursively search the Controls collection. Here is a quick and dirty example.

static class WebHelper
{
  public static IList<T> FindControlsByType<T>(Control root) 
    where T : Control
  {
    List<T> controls = new List<T>();
    FindControlsByType<T>(root, controls);
    return controls;
  }

  private static void FindControlsByType<T>(Control root, IList<T> controls)
    where T : Control
  {
    foreach (Control control in root.Controls)
    {
      if (control is T)
      {
        controls.Add(control as T);
      }
      if (control.Controls.Count > 0)
      {
        FindControlsByType<T>(control, controls);
      }
    }
  }
}

The above can be used as follows

  // Load the Master Page
  var site1Master = LoadControl("Site1.Master");

  // Find the list of ContentPlaceHolder controls
  var controls = WebHelper.FindControlsByType<ContentPlaceHolder>(site1Master);

  // Do something with each control that was found
  foreach (var control in controls)
  {
    Response.Write(control.ClientID);
    Response.Write("<br />");
  }
Chris Taylor
Excellent, that's exactly what I was trying to do and in a much more elegant way. Thanks!
GarryM
@GarryM, I got some time and cleaned the code up a little.
Chris Taylor