1

I have an ASP.NET Web Forms page childPage.aspx with masterPage.aspx as the master page. The childPage.aspx has a user control (userControl.ascx) control defined on it. Now, I am trying to access the controls on childPage.aspx from within the user control. I have tried a handful of different approaches:

HtmlContainerControl ProductMenu = (HtmlContainerControl)Page.FindControl("ProductMenu");

HtmlContainerControl ProductMenu = (HtmlContainerControl)this.Page.FindControl("ProductMenu");

HtmlContainerControl ProductMenu = (HtmlContainerControl)Parent.FindControl("ProductMenu");

HtmlContainerControl ProductMenu = (HtmlContainerControl)this.Parent.parent.FindControl("ContaintHolder").FindControl("ProductMenu")

In above code, ProductMenu is the id of the <div runat="server" /> on childPage.aspx. Now, I am trying to access it from within my user control, but that fails to return the div.

Please help me out. How should I do this? Thanks in advance.

Jeremy Caney
  • 7,102
  • 69
  • 48
  • 77
Rhushikesh
  • 3,630
  • 8
  • 45
  • 82
  • masterPage.aspx is probably masterPage.Master, a real ASP.NET master page? – Marcel Jan 23 '14 at 14:04
  • 1
    I guess, it would be much cleaner and simple, if you give the child control the references to the control you want to access from it. – Marcel Jan 23 '14 at 14:05

1 Answers1

1

The reason this doesn't work is likely because the FindControl() method is not recursive. This is called out in the MSDN documentation:

This method will find a control only if the control is directly contained by the specified container; that is, the method does not search throughout a hierarchy of controls within controls.

So, for instance, Page.FindControls() will only search for controls listed in the Page.Controls collection; it won't search the Controls collection of each of those controls. As such, Page.FindControl() would only work if the ProductMenu were at the top-level of your ASPX page; if it is instead nested within, for instance, a Panel control then this code won't work.

To resolve this, you'll need to write a recursive function to crawl the control tree. For instance:

public Control FindControl(Control parentControl, string controlName) {
  foreach (var childControl in parentControl.Controls) {
    if (childControl.Id == controlName) return childControl;
    var foundControl = FindControl(childControl, controlName);
    if (foundControl != null) return childControl;
  }
  return null;
}

In your case, assuming you'll always be looking for an instance of an HtmlContainerControl, you could even validate the type and return a strongly typed object, should you choose. That said, if you want to keep it strongly typed while still supporting different types, you could instead use a generic:

public T FindControl<T>(Control parentControl, string controlName) where T : Control {
  foreach (var childControl in parentControl.Controls) {
    if (childControl.Id == controlName) return childControl;
    var foundControl = FindControl<T>(childControl, controlName);
    if (foundControl != null && foundControl is T) return childControl;
  }
  return null;
}

In addition, if you'll need to do this repeatedly, you might add this as an extension method to the Page class so it's easily accessible on multiple pages.

Jeremy Caney
  • 7,102
  • 69
  • 48
  • 77