Load a page's control collection via code

Go To StackoverFlow.com

0

I am trying to write a method that will dynamically load a given page's control collection so I can iterate through it and create a list of certain types of controls that reside on the page. The idea is that for any page that inherits from a particular page class, I want to compile a list of editable fields with certain attributes. This all happens outside of these pages (on a different page that is allowing users to manage these other pages).

I've tried both of the following scenarios:

BasePage page = (BasePage)System.Web.Compilation.BuildManager.CreateInstanceFromVirtualPath(string.Format("~/Pages/{0}/Manage.aspx", type.ToString()), typeof(BasePage));

IHttpHandler handler = PageParser.GetCompiledPageInstance(string.Format("~/Pages/{0}/Manage.aspx", type.ToString()), Context.Server.MapPath(string.Format("~/Pages/{0}/Manage.aspx", type.ToString())), HttpContext.Current);
BasePage page = handler as BasePage;

In both situations, the page variable is initiated but the controls collection is blank, presumably because both of these methods are only loading the codebehind and not the markup. How can I dynamically load the page's control collection?

2012-04-04 21:19
by Shane McGarry
Why can't you put your fields in a user control and access that from Page A and Page B? You shouldn't be able to instantiate a page's controls collection until it has been through the full request lifecycle which is not the same as just instantiating an instance of that page - you might find it easier to subclass your fields via UserControls (which you can load on the fly using Page.LoadControl - dash 2012-04-04 22:11


0

I have come across exactly the same requirement of needing to evaluate the controls of a Page A from Page B at runtime.

There is one additional step needed to run the Page through its life cycle. We simply need to call the Page.ProcessRequest() method. Page.ProcessRequest Method (MSDN). The method is hidden from Intellisense.

After this, you will be able to access the controls in the page:

Page page = (Page)BuildManager.CreateInstanceFromVirtualPath("~/MyPage.aspx", typeof(Page));
page.ProcessRequest(HttpContext.Current);

If your page has a master page, you will need to dig down through the master page's place holders.

Be sure to note Microsoft's remarks though:

"You should not call this method."

"This API supports the .NET Framework infrastructure and is not intended to be used directly from your code."

I do not yet know if there are any adverse impacts of doing this.


EDIT: Executing a page within a page can result in a myriad of problems, so I went in a slightly different direction.

Using the HTML Agility Pack, we can load a *.aspx file and recursively traverse its nodes quite easily. If we wanted to find all asp buttons on a page, for example:

private static void FindAllButtonControls(HtmlNodeCollection htmlNodeCollection, List<HtmlNode> controlNodes)
{
    foreach (HtmlNode childNode in htmlNodeCollection)
    {
        if (childNode.Name.Equals("asp:button"))
        {
            controlNodes.Add(childNode);
        }
        else
        {
            FindAllButtonControls(childNode.ChildNodes, controlNodes);
        }
    }
}

public static List<HtmlNode> FindButtonControlsAtVirtualPath(String path)
{
    HtmlAgilityPack.HtmlDocument aspx = new HtmlAgilityPack.HtmlDocument();

    aspx.OptionFixNestedTags = true;
    aspx.Load(HttpContext.Current.Server.MapPath(path));

    List<HtmlNode> controlNodes = new List<HtmlNode>();
    FindAllButtonControls(aspx.DocumentNode.ChildNodes, controlNodes);

    return controlNodes;
}
2013-10-16 05:33
by Timo


0

I wouldn't mess with the page lifecycle. Let ASP.NET manage the control hierarchy on its own, and use some recursive logic to inspect the controls on the page:

protected void Page_Load(object sender, EventArgs e)
{
    if (!Page.IsPostBack)
    {
        FindPanelControls(Page);
    }
}

private void FindPanelControls(Control ctrl)
{
    if (ctrl.HasControls())
    {
        foreach (var childCtrl in ctrl.Controls.OfType<WebControl>())
        {
            //check for certain attributes
            if (childCtrl is Panel)
                Response.Write(childCtrl.ID);

            //recursively call the function for this control
            FindPanelControls(childCtrl);
        }
    }
}
2012-04-04 21:32
by James Johnson
The problem is that I'm sitting on Page B and I just need to get an instance of Page A's control collection so I can see what fields it contains. This is all so I can store information about said fields in the database without having to keep another table that just defines the fields on the page (which is overkill since its already in the markup) - Shane McGarry 2012-04-04 21:34
Why do you need to access page A from page B? Why can't you access page A from page A - James Johnson 2012-04-04 21:35
Because I need to manage a list of fields and my options are either a) use a "relections type" method to get a list of fields on another page that I can use to load into a drop down for user selection or b) create a table in the database of all the fields that we want to let users manage. Option b is bad because as we create new pages or modify existing ones we not only have to add fields to the markup (as per usual web development) but we also need to add said field to the database so it can be managed outside the page. This is to create a rules engine to determine if a field is required - Shane McGarry 2012-04-04 21:44


0

You're over-complicating it; just loop recursively through the Page.Controls collection and check for the type of control you're interested in. Take a look at these earlier questions:

ASP.Net / C#, Loop through certain controls on a page?

Loop through all controls on asp.net webpage

2012-04-04 21:32
by IrishChieftain
The problem is I need to loop through the controls on a page thats not loaded. I'm on Page B. I need Page A's control collection - Shane McGarry 2012-04-04 21:41
Loop through them in Page A on load up and store your values in Session - IrishChieftain 2012-04-04 21:46
I can't guarantee the page has been loaded already - Shane McGarry 2012-04-04 21:47
Use DB table entries for each page. For example: on page A load, update records for that page - bool loaded, etc., and have fields for each type of control (related table - IrishChieftain 2012-04-04 21:49
Actually, on reading your response to James, the idea of using ASP.NET workflow comes to mind.. - IrishChieftain 2012-04-04 22:11
Ads