Rick Strahl's Weblog  

Wind, waves, code and everything in between...
.NET • C# • Markdown • WPF • All Things Web
Contact   •   Articles   •   Products   •   Support   •   Advertise
Sponsored by:
West Wind WebSurge - Rest Client and Http Load Testing for Windows

ASP.NET 2.0 MasterPages and FindControl()


:P
On this page:

Argh. I'm going through an older application and replacing a somewhat complex scheme of user control templating with Master Pages today. For the most part this has been going real well until I hit a page that that relies on page inheritance where there's a common page base class that needs to have access to the controls on the page.

 

ASP.NET has never made this exactly easy, because the base class doesn't allow you access to the controls from the lower level as ASP.NET adds the properties higher up in the hierarchy. In the past I've been working around this by adding properties for the controls to the base class and then overriding these properties, but in ASP.NET 2.0 the control definitions are auto-generate with no chance to override the control definitions. The only workaround has been using FindControl() and dynamically retrieve the control definitions.

 

And this is where things get a bit tricky with MasterPages. The problem is that when you use MasterPages the page hierarchy drastically changes. Where a simple this.FindControl() used to give you a control instance you now have to drill into the container hierarchy pretty deeply just to get to the content container.

 

So in the past I might have done this in my C# base class:

 

protected Label lblError = null;

protected DataGrid dgItemList = null;

 

protected void AssignControls()

{

    this.lblError = this.FindControl("lblError") as Label;

    this.dgItemList = this.FindControl("dgItemList") as DataGrid;

}

 

you now have to drill into the containership with code like this:

 

protected void AssignControls()

{

    this.lblError = this.Master.FindControl("Content").FindControl("lblError") as Label;

    this.dgItemList = this.Master.FindControl("Content").FindControl("dgItemList") as DataGrid;

}

 

This isn't so bad, except when you're trying to figure out how to get to your controls <s>.

 

It really seems lame that Microsoft hasn't added a recursive FindControl() method to the Control class that drills into child containers. While this certainly isn't optimal in terms of performance it sure would make life a lot easier in a lot of situations, and this surely is one of them.

 

Not exactly rocket science to create a method that does this:

 

/// <summary>

/// Finds a Control recursively. Note finds the first match and exists

/// </summary>

/// <param name="ContainerCtl"></param>

/// <param name="IdToFind"></param>

/// <returns></returns>

public static Control FindControlRecursive(Control Root, string Id)

{

    if (Root.ID == Id)

        return Root;

 

    foreach (Control Ctl in Root.Controls)

    {

        Control FoundCtl = FindControlRecursive(Ctl, Id);

        if (FoundCtl != null)

            return FoundCtl;

    }

 

    return null;

}

 

with  this the code becomes:

 

/// <summary>

/// Assigns controls from the subclassed control to this instance so

/// we always can access the controls in our base class.

/// </summary>

protected void AssignControls()

{

this.lblError = wwWebUtils.FindControlRecursive(this.Master,"lblError") as Label;      

this.dgItemList = wwWebUtils.FindControlRecursive(this.Master, "dgItemList") as DataGrid;

}

 

Although this is easier, I suspect it's better to do the explicit thing if that option is available to you as it probably has better performance. Also I suspect Microsoft didn't include this sort of a function in ASP.NET natively because there's potential ambiguity here – there could be more than one control Id that matches a name.


The Voices of Reason


 

scottgu
April 09, 2006

# re: ASP.NET 2.0 MasterPages and FindControl()

Way back when we debated having a recursive FindControl method. One thing we worried about what the performance impact of people mis-using it -- since doing deep walks of the entire control tree lots of time can really slow things down if you don't know what you are doing.

Going back to your problem above, you should be able to just declare the control names as protected fields on your base class -- ASP.NET 2.0 wires these up just like V1.1 does (if a page has a base class and it has the controls already declared, then it doesn't re-generate them on any sub-class).

Hope this helps,

Scott

Rick Strahl
April 09, 2006

# re: ASP.NET 2.0 MasterPages and FindControl()

Scott, thanks for the feedback...

As to using protected properties for the control in the base - that doesn't work. I think that works if the properties are defined in the partial class, but not with the base class.

I have:

ItemListBase.cs (controls defined)

which is then inherited by the ASPX.cs partial classes. In there I can see the controls defined in ItemListbase.cs - in code inside of ItemListBase - is null.

So the way I work around this now is that I have a method AssignControls() that goes out and does a bunch of FindControl calls to retrieve controls and explicitly assign them.

I'm not sure why this should be so - the controls are obviously visible in the partial class higher up in the class hierarchy, so I'm not sure why they shouldn't be visible in the base class. The only thing I can defer from this is that ASP.NET creates teh new properties with the 'new' keyword so they override the base controls.


Scott Allen
April 10, 2006

# re: ASP.NET 2.0 MasterPages and FindControl()

Rick:

Try using CodeFileBaseClass in your @ Page directive. This let's the ASP.NET code generator find those protected fields in your base class and wire them to the controls in the aspx.

I wish we didn't need to use this attribute, it feels messy.


Rick Strahl
April 10, 2006

# re: ASP.NET 2.0 MasterPages and FindControl()

Aaargh. Thanks Scott. That does indeed work. I had no idea about this directive and yes: It seems odd that this should be required. I can see the possible need to explicitly have things not stored on the base class, but I'd think that'd be the exception to the rule not the other way around.

Still, all things considered this is cleaner than my use of a set of FindControl() calls.

Bill Swartz
April 14, 2006

# re: ASP.NET 2.0 MasterPages and FindControl()

Rick, I ended up having to use this in your MessageDisplay sample. I've embedded the MessageDisplay page in a MasterPage and as you might suspect the FindControl didn't work. Funny thing was when researching why it didn't work, Google pointed me to a solution written by the same guy who wrote the MessageDisplay example..

Thanks on both counts.
Bill

Rick Strahl
April 14, 2006

# re: ASP.NET 2.0 MasterPages and FindControl()

Bill, the solution to MessageDisplay is the CodeFileBaseClass attribute - if you specify that you won't need FindControl or FindControlRecursive to get at the controls.

And yes, this was part of the reason that this actually came up <g>...

Siva
April 27, 2006

# re: ASP.NET 2.0 MasterPages and FindControl()

Rick,
I have a dropdownlist inside the gridview as a template column defined as follows:
<asp:TemplateField HeaderText="Choose Location">
<ItemTemplate>
<asp:DropDownList ID="ddlChooseLoc" runat="server">
</asp:DropDownList>
</ItemTemplate>
</asp:TemplateField>
I have the gridview inside of a master page- content hierarchy.
I have declared the CodeFileBaseClass in your @ Page directive; I have also declared a variable of the type dropdownlist in the base class.
When I try to access it from the partial class I am getting a null value for the dropdownlist variable.
I even tried to a FindControl on the dropdownlist still I am getting a null.
Any idea what I may be missing?
Thanks
-Siva

Siva
April 28, 2006

# re: ASP.NET 2.0 MasterPages and FindControl()

I fixed it by adding a line to check if it is a datarow and only then I am doing a FindControl.

Sam
April 29, 2006

# re: ASP.NET 2.0 MasterPages and FindControl()

Thanks,

You saved me a lot of time with the FindControlRecursive advice.

Sam

Sean Williams
May 16, 2006

# re: ASP.NET 2.0 MasterPages and FindControl()

I have an issue with FIndControl that is driving me crazy. I have taken the old IssueTracker Startup Kit and modified it extensively for my owb use. It worked fine in 1.1, but on converting to 2.0 my FindControl isn't behaving as desired.

I've looked at every MSDN ocurrance of the method as well as trolled the various .NET sites but nothing seems to solve my issue.

Anyway, I have a dropdownlist set into a panel of a UserControl. That user control is set on the main page of the IssueDetails. I use findCOntrol to find the dropdownlist (and it does) but the value isn;t captured. Any ideas? I cannot believe that the difference between 1.1 and 2.0 is so great that this simple method now fails...

Sean~

PS: I like the recursive find... a great tool if you don;t want to dig into the debug windows to find the path explicitly...:)

KSVN
May 19, 2006

# re: ASP.NET 2.0 MasterPages and FindControl()

I have a similar issue.

I have a dropdown in the master page that I need to repopulate my child page when the dropdown posts back. I can not get the value of the dropdown in the child page. I tried the findcontrol but does not give me a result.

Drew
June 27, 2006

# re: ASP.NET 2.0 MasterPages and FindControl()

Hi Rick...

I have a similar issue, I have been setting up the master page main content placeholder as its own variable...like thus...

Dim main As ContentPlaceHolder = CType(Master.FindControl("MainContent"), ContentPlaceHolder)

Then all other findcontrols are just main.findcontrol("yourcontrol"). If you were to setup the main content placeholder for this.Master.FindControl("Content") in your example above as its own variable, would it make drilling down quicker and easier to code, as it dosnt have to go back to find the masterpage contentplaceholder control to any find childern...?

Rick Strahl
June 28, 2006

# re: ASP.NET 2.0 MasterPages and FindControl()

Drew,

That only solves part of the problem. If you have other containers inside the master container you still need to drill into that. So yes it's good to bypass a step if you know it's there, but ultimately you may still need to drill deeper to find controls.

It's always best to find controls at the right level. It's usually generic code that has to use FindControl() in the first place so in those cases you usually don't have any control over what's actually available.

Simon C
July 02, 2006

# re: ASP.NET 2.0 MasterPages and FindControl()

Rick,
This looks just what I am trying to resolve myself, but in VB. I have a Grid view (GridView1) contained in a master page and I am trying to store the value of the selected records key in a session control.
So I have set up
Dim MasterGridView As GridView = CType(Master.FindControl("GridView1"), GridView)
but I am still getting a System.NullReferenceException.
My Sub routine then contains NewText = MasterGridView.SelectedRow.Cells(0).Text
in order to try and store the records ID.
Any views on how this type of issue can be reolved?


Rick Strahl
July 02, 2006

# re: ASP.NET 2.0 MasterPages and FindControl()


Check the page to make sure what your container ship is. If the grid sits inside of another container - a panel or even a div with runat=server your containership stack is blown and FindControl won't find the control.

One way to see the container ship is to print the UniqueID of the control to the Web form - that'll show the names in the chain.

Rick Strahl
July 02, 2006

# re: CodeFileBaseClass

As a sidenote to K. Scott Allen's comment about CodeFileBaseClass - this directive only works with direct page inheritance. If you have two pages that derive from the same CodeBeside class, and both both a have CodeFile= pointing at the same .cs or .vb file then CodeFileBaseClass works fine.

However, if you define your base class one level higher in the class hierarchy (ie. Page -> MyPageBaseClass -> MyPage1 -> MyPage2) you can't use CodeFileBaseClass to point at MyPageBaseClass. This means any truly generic Page subclass that doesn't have a visual ASPX file associated with it won't be able to see the any controls defined higher up in the tree even if the properties are defined at the base level.


elpako
August 03, 2006

# re: ASP.NET 2.0 MasterPages and FindControl()

Before I start seeking something about FindControl problem I find the same solution. Like we see - great minds thinking alike

Best

Milind Amin
August 18, 2006

# re: ASP.NET 2.0 MasterPages and FindControl()

Good One!!!

Great to know about it.

Keep it up.

Mick
September 12, 2006

# re: ASP.NET 2.0 MasterPages and FindControl() for dynamically created IDs

Hello all, I'm new to ASP.NET 2.0, and .NET in general, but I think my problem has similar bearing on this topic.

I am using a repeater to display a collection list on a content page and am using a master page. As the data is being bound to the repeater I'm attempting to dynamically generate TextBox IDs so that I can later associate the contents of each TextBox with the collection list object it's data was populated from.
((TextBox)e.Item.FindControl("txtBox")).ID = "txt_" + tempObjectList.FiscalYear.ToString();

So if the contents of the TextBox changes, I can save it back to the liste object it is associated with.
I am however having quite a time trying to access the TextBox ID after its assigned.
For example, if I set the ID = "txtbox_01" and try to access it using a find control, it breaks and gives me an "Object reference not set to an instance of an object" error. When I look at the page source, the TextBox ID is set to id="ctl00_contentBody_txt_01".
When trying to perform some action on the data in the TextBox I try to access it as follows:
((TextBox)FindControl("txt_" + tempObject.FiscalYear.ToString())).Text

Any help would be greatly appreciated!

Thanks,
Mick

Prakar
September 28, 2006

# re: ASP.NET 2.0 MasterPages and FindControl()

Nice piece of code. It solved my problem of 2 days.

I have a UserControl form and everything is done there. only thing I do in aspx page is to call usercontrol and pass parameters. all this worked fine till I was not using MasterPages. When I started using MP, I got error "Object not referenced..." in my code behind for aspx page. I'll do somemore testing but it seems working fine after I added recursive FindControl.

thanks bunch.

Web Forms
September 28, 2006

# ASP.NET Forums - Problem Findcontrol and Masterpage


Web Forms
October 02, 2006

# ASP.NET Forums - FindControl

# ASP.NET Forums - FindControl() doesn't work if page has MasterPage

# ASP.NET Forums - contentplaceholder - how to loop through form values ?


Data Presentation Controls
October 13, 2006

# ASP.NET Forums - Storing the Key from GridView


sj
November 10, 2006

# re: ASP.NET 2.0 MasterPages and FindControl()

I've an issue accessing content page's control with the use of master page.

Here is the code snippet

1. This is the declaration in the master page (masterPage.master)
<asp:ContentPlaceHolder ID="contentID" runat="server">
</asp:ContentPlaceHolder>


2.This is the declaration in the content page (content.aspx)
<asp:Content ID="contentID" runat="Server" ContentPlaceHolderID="contentDetails">
<asp:Label ID="Label1" runat="server" Text="Fisrt Text"></asp:Label>
</asp:Content>

3. Onpageload I'm trying to change the value of Label1 to "Second Text"
I have written the below code to do so but it is doing nothing. When the page loads I see "First Text", where in I'm expecting "Second Text"


Here are the couple of approach I took
1. Find control method

In conent.aspx.cs on Page_Load event I have the below code.

ContentPlaceHolder cnt;
cnt= (ContentPlaceHolder) Page.Master.FindControl("contentDetails");

Label lbl;
lbl= (Label) FindControlRecursive(this.Master, "Label1");
lbl.Text = "Second Text";


2. I Tried setting <%@ MasterType VirtualPath="~/masterPage.master" %>
but no luck..

3. I tried FindControlRecursive()
still it doesn't work

Anyone has any idea what is going wrong here??

thanks in advance.
-sj

# ASP.NET Forums - DropDownList based on data Control inside another Control


steve
November 29, 2006

# re: ASP.NET 2.0 MasterPages and FindControl()

I'm stuck on a problem which may be in a similar area, but I think don't have as much as 0.1% of Rick's know how, and I'm struggling!

I've written code to make my content page modify my master page, no problem, but now I'm looking at trying to place a version of this code as a method in the masterpage codebehind. My thinking was that this way I wouldn't have to add the code to all of the content pages. Codebehind in the content pages could simply call the relevant method. My problem was that I couldn't get masterpage codebehind to affect controls on the masterpage - I tried various permutations of FindControl, but I couldn't get it to work - "Object reference not set to an instance of an object".

I'd have thought that referencing a control on the masterpage from the masterpage codebehind would be easier, but I haven't been able to do it...

Any thoughts welcome, apologies if this is something of newbie query.

Rick Strahl
November 29, 2006

# re: ASP.NET 2.0 MasterPages and FindControl()

Well as this entry mentions FindControl() only finds controls at the current level of containership, so maybe you're not pointing at the right parent control to use FindControl? Using FindControlRecursive() should do the trick though if you start Page as the Root control.

Data Presentation Controls
December 08, 2006

# ASP.NET Forums - MasterPage with PlaceHolder containing a Formview and iteration


Daniel
December 19, 2006

# re: ASP.NET 2.0 MasterPages and FindControl()

hehe...so many people with the same problem.

Instead of iterating through the controls and do recurvise methods on the hierachy, try using the event called ItemDataBound. ItemDataBound is available on all of the Grid's (Repeater, GridView, DataGrid, etc)

The ItemDataBound gives you the ItemEventArgs for the control you are using.

I have an repeater which is placed inisde a MasterPage, in the repeater i have several Label control. So how do I find these Labels ?

Look here:

protected void rptTemplates_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.Header || e.Item.ItemType == ListItemType.Footer)
{
foreach (Control ctrl in e.Item.Controls)
{
//Got ya...
}
}
}

Inside the foreach I have my labels...

Web Forms
January 16, 2007

# ASP.NET Forums - FindControl() problem


djeeg blog
January 17, 2007

# djeeg blog: CodeFileBaseClass to the rescue of Page Inheritance


Daniel
January 19, 2007

# re: ASP.NET 2.0 MasterPages and FindControl()

I am having a problem. I have my control inside an UpdatePanel>MultiView1>View1>asp:table and I can't find it.

I am generating some usercontrols (A) inside another usercontrol (B) and calling usercontrol (B) in an .aspx page that has a masterpage.

So, my aspx page calls the master page, and inside the container of the masterpage I call my usercontrol B. This usercontrol generates dynamically usercontrols of type A inside an asp:table. The asp:table is inside a View1, and the View1 is inside a Multiview1, and the Multiview1 is inside an Update Panel.

This is my html code (I should mention that control A has a checkbox, and 2 dropdownlists:

//This is usercontrol B and I register usercontrol A in this page
<%@ Register ... src="~/usercontrol_A.ascx" ... %>

<asp:UpdatePanel ID="UpdatePanel1" runat="server">
 <ContentTemplate>
  <asp:MultiView ID="MultiView1" runat="server">
   <asp:View ID="View1" runat="server">
     <asp:Table runat="server" ID="offeredMenusTable" Width="720px"></asp:Table>
   </asp:View>
  </asp:MultiView>
 </ContentTemplate>         
</asp:UpdatePanel>


//This is the codebehind for this page:

//This creates the controls just find
private void create()
{
 TableRow trItem = new TableRow();//New <tr>
 TableCell tdItem = new TableCell();//New <td>
 TableCell tdItem2 = new TableCell();//New <td>
 
for(int i=0; i < 5; i++)
 {
   ns.ucs.uc_A.uc_A ckBox = (ns.ucs.uc_A.uc_A)LoadControl(@"~/ns/ucs/uc_/.uc_A.ascx");
   ckBox.ID = menuItemID.ToString() + "|" + i;

   tdItem.Controls.Add(ckBox);
   trItem.Cells.Add(tdItem);
   this.offeredMenusTable.Rows.Add(trItem);
   //this.offeredMenusTable.Controls.Add(trItem); I tried this, but no luck finding it either

  _arrlstFoodItemIDs.Add(ckBox.ID);//Adding the ckBox IDs to an ArrayList
 }
  Session["_arrlstFoodItemIDs"] = _arrlstFoodItemIDs;
}


//But when I try to find them the FindControl returns null

void checkAll()
{
  _arrlstFoodItemIDs = (ArrayList)Session["_arrlstFoodItemIDs"];
   
 for (int i = 0; i < _arrlstFoodItemIDs.Count; i++)
 {
   ns.ucs.uc_A.uc_A ckBox = (ns.ucs.uc_A.uc_A)LoadControl(@"~/ns/ucs/uc_/.uc_A.ascx");
   ckBox=this.FindControl(_arrlstFoodItemIDs[i].ToString()) as ns.ucs.uc_A.uc_A;
   
    //The line above returns null 

    if(ckBox._CbBoolVal == false)//_CbBoolVal-checks the usercontrol A checkbox
   {
     ckBox._CbBoolVal  = true;
   }
  }
}

//As I said before I generate the usercontrols (A) fine, but I can't find them. I've been working on this problem for 3 days now. So, any help is appreciated. Thank you!!!

# PreviousPage к MasterPage


Web Forms
February 21, 2007

# ASP.NET Forums - Server Control dynamic access


dan m
March 02, 2007

# re: ASP.NET 2.0 MasterPages and FindControl()

did you fix your problem djeeg blog ? I have a similar issue with a control that cant be resolved with the recurursive function - its a multiview within a formview template..

cheers, dan

Bill B
March 12, 2007

# re: ASP.NET 2.0 MasterPages and FindControl()

This code will locate a linkbutton and a user control on a master page.
The below code is in the load event of the content page.
Usercontrol is a generic type.

Dim headerlnk As LinkButton
Dim menuCtl As UserControl
menuCtl = CType(Master.FindControl("SiteMapCtl1"), UserControl)
menuCtl.Visible = False
headerlnk = CType(Master.FindControl("lnkUnits"), LinkButton)
headerlnk.Visible = True

Joshua Beall
March 16, 2007

# re: ASP.NET 2.0 MasterPages and FindControl()

I've done a tiny bit of benchmarking on recursive FindControl calls, and I'm satisfied that it will be fast enough for me. On my dev workstation (single core P4 running at 3.6GHz, 2 gigs of RAM), .NET could do a recursive control lookup through a page with 115 controls lightning fast. I got only 0ms results. I added System.Threading.Thread.Sleep(75) just to make sure that my timing code was correct (it was).

Keep in mind that many systems (mine included) don't have a timer resolution of less than about 16ms. See here:
http://www.eggheadcafe.com/articles/20021111.asp
So the fact that I am always getting 0ms results really means that it is finishing in less than 16ms. Still blazing fast, in my opinion.

But don't take my word for it; try timing it yourself. But I'm satisfied that a recursive control lookup will work fine for my purposes. I've override the Page.FindControl method with a recursive lookup for my MasterPage-enabled apps.

-Josh

Rick Strahl
March 16, 2007

# re: ASP.NET 2.0 MasterPages and FindControl()

Joshua a single call to FindControlRecursive isn't going to kill you, but many calls will probably become noticable especially on large forms and especially if a control is deep in the stack or not found at all. For occasional calls when you need to drill down it's no problem at all, but if you're a control developer who's looking at every control on the page it would be a problem.

I think Scott's point of why they didn't put it in the product makes some sense although I still would love to see an optional parameter on FindControl to do the recursive lookup, rather than having a separate function. OTOH, I suspect anything we write on our end ourselves is likely to be faster than what Microsoft writes for us since they check for every possible failure/security scenario etc. <s> which is as it should be...

Joshua Beall
March 19, 2007

# re: ASP.NET 2.0 MasterPages and FindControl()

You're probably right; it would become noticeable on large forms where there were lots of calls.

However, I'd still say, do some benchmarking before you say "it will work fine" or "it will be too slow." In my case I think it's going to work great. Let's say that it does add 12ms per lookup -- that means doing 5 lookups would cost me 60ms. Looking at the trace output for one of the forms I'm working on right now, i can see that total page generation time is about 900ms. That's about a 7% performance difference one way or the other. To me, that's acceptable. To others, maybe not.

Joshua Beall
March 19, 2007

# re: ASP.NET 2.0 MasterPages and FindControl()

That's a 7% performance difference, assuming that finding the control non-recursively incurse *no* performance hit at all; probably unrealistic. To find out the real performance difference, you'd have to try both methods and compare them.

Parimal
April 04, 2007

# re: ASP.NET 2.0 MasterPages and FindControl()

Hi,
How can i access the method wriiten in the Content Place Holder ASPX page from master page as the ASPX page gets loaded first than the Master Page load event?

Parimal

Rick Strahl
April 04, 2007

# re: ASP.NET 2.0 MasterPages and FindControl()

You should never access content page content from a master page. If you have common code that needs to be accessible it should probably be contained in the master page.

You can always get access to the page through this.Page() in the master and then casting to your sepcific page type.

Parimal
April 05, 2007

# re: ASP.NET 2.0 MasterPages and FindControl()

Hi,

Thanks for the reply. I have a tab strip in Master Page and a Main ASPX page in COntent Place holder. We want to dynamically load the User Controls in the Panel in ASPX page when tab items are clicked. But the Problem is that ASPX page load event gets fired before Master Page events. SO ASPX page dont get what tab is clicked. So we want to access the ASPX page method for loading the USer control in the TAB click event of master page.

How to resolve these issue?

Thanks in Advance,

Parimal

Getting Started
April 26, 2007

# ASP.NET Forums - Control Visibility


Alfred Ruffner
April 26, 2007

# re: ASP.NET 2.0 MasterPages and FindControl()

This technique actually made my eveining ..... Thanks

ASP.NET Forums
May 19, 2007

# Problem Findcontrol and Masterpage - ASP.NET Forums


ASP.NET Forums
May 19, 2007

# contentplaceholder - how to loop through form values ? - ASP.NET Forums


ASP.NET Forums
May 21, 2007

# FindControl() doesn't work if page has MasterPage - ASP.NET Forums


ben
May 21, 2007

# re: ASP.NET 2.0 MasterPages and FindControl()

Thanks for this very good report!
I though, this is a bug, that the following code not work.
Control ctrl = this.FindControl("control");


thx ben

ASP.NET Forums
May 29, 2007

# FindControl() problem - ASP.NET Forums


ASP.NET Forums
May 31, 2007

# Server Control dynamic access - ASP.NET Forums


ASP.NET Forums
June 06, 2007

# MasterPage with PlaceHolder containing a Formview and iteration - ASP.NET Forums


ASP.NET Forums
June 16, 2007

# Solution to the FindControl problem - ASP.NET Forums


ASP.NET Forums
June 17, 2007

# Storing the Key from GridView - ASP.NET Forums


ASP.NET Forums
June 25, 2007

# FindControl - ASP.NET Forums


Arvind
July 04, 2007

# re: ASP.NET 2.0 MasterPages and FindControl()

Another solution ...

Create a base class which inherits Page

Public Class DashBoardPage
Inherits System.Web.UI.Page

Then write a function in base class ....

Protected Overloads Function FindControl(ByVal id As String) As System.Web.UI.Control
Return Page.Master.FindControl("cphForm").FindControl(id)
End Function

Now use it in Partial class. (cphForm = Your main content area id on master page )

ASP.NET Forums
July 10, 2007

# DropDownList based on data Control inside another Control - ASP.NET Forums


Robert MacLean
July 22, 2007

# re: ASP.NET 2.0 MasterPages and FindControl()

You can do a cleaner containership drilldown by using the $ delimeter. Taking your first example it could become:
this.Master.FindControl("Content$lblError") as Label;

Rick Strahl
July 22, 2007

# re: ASP.NET 2.0 MasterPages and FindControl()

Robert you really shouldn't rely on the naming nor the containership like this. It works sure, but the naming is up to ASP.NET and that may change in the future. Also using the exact syntax above assumes you know the exact hierarchy of the controls down the control tree - if you know where the control lives exactly there would be no need to use FindControl in the first place. That'd be like doing FindControl(this.lblError.UniqueId) which is kinda non-sensical <s>.

Robert MacLean
July 22, 2007

# re: ASP.NET 2.0 MasterPages and FindControl()

I think you have missed what I have shown, the syntax is: <Master Page Content ID>$<Control ID>. It is no using the generated IDs (agreed those could change and thus shouldn't be used) but the ID you assign them at design time.

As for needing to recurse, the control can exist anywhere on the content page (even as a sub control), so the need to recurse is removed.

The only case where I could see you having an issue is if you have a master page within a master page, but since the designer doesn't support that I doubt anyone would hit that sort of issue).

To use your assign controls example. The only real change is the removing of the second FindControl :
protected void AssignControls()
{
    this.lblError = this.Master.FindControl("Content$lblError") as Label;
    this.dgItemList = this.Master.FindControl("Content$dgItemList") as DataGrid;
}

Martin Blais
August 06, 2007

# re: ASP.NET 2.0 MasterPages and FindControl()

Robert's solution work great for me and much easier to understand for me

Rick Strahl
August 06, 2007

# re: ASP.NET 2.0 MasterPages and FindControl()

Robert - my point was that if you *know* the control path you can usually just reference the control directly or use FindControl on the appropriate container.

The recursive deal is useful in situations and required when you don't know the control path and you need to find a control. This is a common scenario in generic control development when one control interacts with others on the page.

dotnetuncle
August 20, 2007

# re: ASP.NET 2.0 MasterPages and FindControl()

Seems this method aint working when used to find a control within an update panel recursively.

Vishal Khanna

navneet
August 23, 2007

# re: ASP.NET 2.0 MasterPages and FindControl()

i am having problem while accessing dynamic control id of radio button.i am using master pages.with the help of findcontrol method i m doing bt 1 error came null value reference....please anybody help me.....thanx

Eric
September 21, 2007

# re: ASP.NET 2.0 MasterPages and FindControl()

This article helped with my issues using 'this.FindControl'.

Thanks.

Barry
October 02, 2007

# re: ASP.NET 2.0 MasterPages and FindControl()

This was a helpful article, as were the comments.

I have a similar setup where I have a hierarchy of classes in my pages. I have a base page class, a site page class, a forum page class, and a page type class. The base page class implements application logic. The site page class implements functionality unique to the site, as the application runs on several sites. The forum page class implements functionality specific to forums (areas), and the page type class implements specific page type functionality (Contact Us Page, Discussion Page, Chat Page, etc.)

I needed for the base page class to have access to several controls on the page, and I didn't want to make several calls to FindControl as I assumed the performance would be terrible. What I did was register control names in the Page.Init. Effectively, I built a collection/array of control names. Any of the page classes in the hierarchy could add to this array. Effectively, they were saying "I'm going to need access to control xyzzy. Please find it for me." Then, in the base page class's load method, I manually traversed the page's control tree. Each time I found a control name that matched one that had been registered, I added a reference in another collection to that control. MyPageControls("xyzzy") = Object. After this routine ran, each of the page classes could access the controls they needed via the collection.

I still wasn't overly fond of this, but it seemed much more efficient than calling Page.FindControl 30 or 40 times.

Eventually, I added a prefix to control names that needed to be identified. This way I was a little more efficient in the code. I could then say "If left(Control.ID,4)="XYZ_" then MyPageControls.Add(Control.ID,Control)". This seemed a bit more efficient since I didn't have to traverse/search a collection of control names for each control I found.

NOW, I find this! (Thank you Google for bringing this page up when I searched on "asp.net findcontrol performance".)

It seems that performance would benefit from using the "CodeFileBaseClass" directive.

Thanks! (And I hope I didn't miss something by not reading all of the posts!)

Barry
October 02, 2007

# re: ASP.NET 2.0 MasterPages and FindControl()

I called it...

Rick Strahl (7/2/06) pegged it. If you have a deeper page hierarchy, you're screwed on that whole CodeFileBaseClass solution.

Guess I'll stick with my existing solution.

Chris
November 30, 2007

# re: ASP.NET 2.0 MasterPages and FindControl()

Hi, spent ages trying to get this to work. After reading the code above a second time I got this working perfectly. Thank you very much!

Wyatt Wong
December 12, 2007

# re: ASP.NET 2.0 MasterPages and FindControl()

I am not sure whether Rick's code can be used to locate controls that are buried inside DataGrid, GridView, Repeater, etc. However, I found another resource on the Internet titled "In Search of ASP.Net Controls" which can be found in http://www.odetocode.com/articles/116.aspx

I recently got into a problem in finding a TextBox inside a Repeater control in a MasterPage environment and I finally got the solution with the following code:

this.Repeater1.DataSource = ds; // ds is some data source
this.Repeater1.DataBind(); // Bind the Repeater1 with the data source

// Locate the TextBox control in a MasterPage environment
// i is the row number where TextBox is located inside the Repeater

TextBox tb = this.Master.FindControl("ContentPlaceHolder1").FindControl("Repeater1").Controls[i].FindControl("MyTextBox") as TextBox;

Brent VanDusen
January 01, 2008

# re: ASP.NET 2.0 MasterPages and FindControl()

Caught your presentation at Dev Connections in Vegas. Always good - I also read your blog on the airline trip to get there - lol (been there done that too). This article solved my problem quickly. I figured that the control was buried inside the master page container. I just needed the syntax- which you had. It reminds me of how you have to access child controls in a custom control.

Nicolette
January 04, 2008

# re: ASP.NET 2.0 MasterPages and FindControl()

Thank you <b>soo</b> much! I spent almost 2 days trying to find the solution to this.
I kept encountering this error: System.NullReferenceException "Object reference not set to an instance of an object". However, when I did a Watch I was able to see the previous page's controls (with their values), and that left me scratching my head.

<b>Here's my old code</b>
using System;
using System.Configuration;
using System.Collections;
using System.Data;
using System.IO;
using System.Security.AccessControl;
using System.Security.Permissions;
using System.Security.Principal;
using System.Security;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;

public partial class PODResults : System.Web.UI.Page
{
private DatabaseManager DBM = new DatabaseManager();
protected DataTable resultDT = new DataTable();
private Int16 rowCt = 0;
private Int64 executionTime = 0;
private string criteria = "";

protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
try
{
string pagename = "";
if (PreviousPage != null && PreviousPage.IsCrossPagePostBack)
{

pagename = PreviousPage.ToString();
criteria = ((TextBox)PreviousPage.FindControl("txtCriteria")).Text;
resultDT = DBM.PODiscrepancy(criteria);
resultDT.AcceptChanges();
rowCt = (Int16)resultDT.Rows.Count;

}


if (rowCt == 0)
{ /* Let user know that there were no results.
disable the buttons on the search results
*/
BtnExcel.Visible = false;
//BtnClr.Visible = false;
//msg_Lbl.Text = "No Records Found";
//msg_Lbl.ForeColor = System.Drawing.Color.Red;
} //end if


} //end try

catch (Exception ex)
{
Console.WriteLine("Application caught exception. Exception found at {0}", ex.StackTrace);
}
finally
{
Session["PODRequestEnd"] = System.DateTime.Now;
Session["PODExecutionTime"] = (System.DateTime.Now.Ticks - ((DateTime)Session["PODRequestStart"]).Ticks) / 600000000; //convert ticks to minutes 1 minute = 600,000,000 ticks

executionTime = (Int64)Session["PODExecutionTime"];
rowCt = (Int16)resultDT.Rows.Count;
if (rowCt > 0)
{
//Finally, I can begin to work with the data set.
Session["PODResultsDataTable"] = resultDT;
rptPODResults.DataSource = resultDT;
rptPODResults.DataBind();
OnExportGridToCSV();
//Response.Write("finally");
}
}//end finally

} //end if
else
{ // IsPostBack


//Finally, I can begin to work with the data set.
resultDT = (DataTable)Session["PODResultsDataTable"];
rowCt = (Int16)resultDT.Rows.Count;
rptPODResults.DataSource = resultDT;
rptPODResults.DataBind();
//Response.Write("finally");


}

return;


} //Page_Load()

public void BtnExcel_Click(object sender, System.EventArgs e)
{ //or I can use the same exact code that I used to create the CSV file and put a ".xls" extension on the filename.
try
{

if (rowCt > 0)
{
DataGrid myDataGrid = new DataGrid();
myDataGrid.DataSource = resultDT;
myDataGrid.DataBind();

Response.Clear();

Response.AddHeader("content-disposition", "attachment;filename=" + Convert.ToString(DateTime.Now.ToString()) + "_PODiscrepancyResults.xls");

Response.Charset = "";

Response.Cache.SetCacheability(HttpCacheability.NoCache);

Response.ContentType = "application/vnd.ms-excel";

System.IO.StringWriter stringWrite = new System.IO.StringWriter();

System.Web.UI.HtmlTextWriter htmlWrite = new HtmlTextWriter(stringWrite);

myDataGrid.Controls.Clear();

myDataGrid.RenderControl(htmlWrite);//Tell the datagrid to render itself to our htmltextwriter

Response.Write(stringWrite);

//Response.End();
HttpContext.Current.ApplicationInstance.CompleteRequest();
}
else
Response.Write("Error not caught: Zero Rows To Display!");
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
Response.Write(ex.Message);
}

return;

}//BtnExcel

private void OnExportGridToCSV()
{


//string currentUser = WindowsIdentity.GetCurrent().Name.ToString();

//DirectorySecurity ds = Directory.GetAccessControl(Server.MapPath("~/OutputFiles/"));

//AuthorizationRuleCollection arc = ds.GetAccessRules(true, true, typeof(System.Security.Principal.NTAccount));

//string sas = WindowsIdentity.GetCurrent().Groups.ToString();
//string pUser = Page.User.Identity.Name;
//string wUser = System.Security.Principal.WindowsIdentity.GetCurrent().Name;
//string currentPrincipal = System.Threading.Thread.CurrentPrincipal.Identity.Name;



try
{
if (rowCt > 0)
{
// Create the CSV file to which grid data will be exported.

string fileName = DateTime.Now.ToShortDateString() + "_PODiscrepancyResults.csv";
fileName = fileName.Replace("/", "");
string fileNameAndPath = Server.MapPath("~/OutputFiles/") + fileName;
//StreamWriter sw = new StreamWriter(Server.MapPath("~/OutputFiles/"+fileName), false);

int iColCount = resultDT.Columns.Count;
if (File.Exists(fileNameAndPath))
{
File.Delete(fileNameAndPath);
}
StreamWriter sw = File.CreateText(fileNameAndPath);

// First we will write the headers.

for (int i = 0; i < iColCount; i++)
{
// Can pick out the specific columns. Do not write all the data that's in the GRID.not useful to user
sw.Write(resultDT.Columns[i].ColumnName);
if (i < iColCount - 1)
{
sw.Write(",");
}
}
sw.Write(sw.NewLine);
// Now write all the rows.
foreach (DataRow dr in resultDT.Rows)
{

for (int i = 0; i < iColCount; i++)
{
//pick out the specific columns. Do not write all the data that's in the GRID.not useful to user
if (!Convert.IsDBNull(dr[i]))
{
sw.Write((string)dr[i]);
}
if (i < iColCount - 1)
{
sw.Write(",");
}
}
sw.Write(sw.NewLine);
}
sw.Close();




} // if (resultDT.Rows.Count > 0)
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}//end ExportGridToCSV

}





<div style="background-color:blue; width:100%;height:20px;"> &nbsp;</div>
<b>Here is my new code</b>
--------------------------------------------------------
using System;
using System.Configuration;
using System.Collections;
using System.Data;
using System.IO;
using System.Security.AccessControl;
using System.Security.Permissions;
using System.Security.Principal;
using System.Security;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;

public partial class PODResults : System.Web.UI.Page
{
private DatabaseManager DBM = new DatabaseManager();
protected DataTable resultDT = new DataTable();
private Int16 rowCt = 0;
private Int64 executionTime = 0;
protected string criteria = "";

protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
try
{
string pagename = "";
if (PreviousPage != null && PreviousPage.IsCrossPagePostBack)
{



criteria = ((TextBox)PreviousPage.Master.FindControl("content").FindControl("txtCriteria")).Text;

criteria = ((TextBox)PreviousPage.FindControl("txtCriteria")).Text;
resultDT = DBM.PODiscrepancy(criteria);
resultDT.AcceptChanges();
rowCt = (Int16)resultDT.Rows.Count;

}


if (rowCt == 0)
{ /* Let user know that there were no results.
disable the buttons on the search results
*/
BtnExcel.Visible = false;
//BtnClr.Visible = false;
//msg_Lbl.Text = "No Records Found";
//msg_Lbl.ForeColor = System.Drawing.Color.Red;
} //end if


} //end try

catch (Exception ex)
{
Console.WriteLine("Application caught exception. Exception found at {0}", ex.StackTrace);
}
finally
{
Session["PODRequestEnd"] = System.DateTime.Now;
Session["PODExecutionTime"] = (System.DateTime.Now.Ticks - ((DateTime)Session["PODRequestStart"]).Ticks) / 600000000; //convert ticks to minutes 1 minute = 600,000,000 ticks

executionTime = (Int64)Session["PODExecutionTime"];
rowCt = (Int16)resultDT.Rows.Count;
if (rowCt > 0)
{
//Finally, I can begin to work with the data set.
Session["PODResultsDataTable"] = resultDT;
rptPODResults.DataSource = resultDT;
rptPODResults.DataBind();
OnExportGridToCSV();
//Response.Write("finally");
}
}//end finally

} //end if
else
{ // IsPostBack


//Finally, I can begin to work with the data set.
resultDT = (DataTable)Session["PODResultsDataTable"];
rowCt = (Int16)resultDT.Rows.Count;
rptPODResults.DataSource = resultDT;
rptPODResults.DataBind();
//Response.Write("finally");


}

return;


} //Page_Load()

public void BtnExcel_Click(object sender, System.EventArgs e)
{ //or I can use the same exact code that I used to create the CSV file and put a ".xls" extension on the filename.
try
{

if (rowCt > 0)
{
DataGrid myDataGrid = new DataGrid();
myDataGrid.DataSource = resultDT;
myDataGrid.DataBind();

Response.Clear();

Response.AddHeader("content-disposition", "attachment;filename=" + Convert.ToString(DateTime.Now.ToString()) + "_PODiscrepancyResults.xls");

Response.Charset = "";

Response.Cache.SetCacheability(HttpCacheability.NoCache);

Response.ContentType = "application/vnd.ms-excel";

System.IO.StringWriter stringWrite = new System.IO.StringWriter();

System.Web.UI.HtmlTextWriter htmlWrite = new HtmlTextWriter(stringWrite);

myDataGrid.Controls.Clear();

myDataGrid.RenderControl(htmlWrite);//Tell the datagrid to render itself to our htmltextwriter

Response.Write(stringWrite);

//Response.End();
HttpContext.Current.ApplicationInstance.CompleteRequest();
}
else
Response.Write("Error not caught: Zero Rows To Display!");
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
Response.Write(ex.Message);
}

return;

}//BtnExcel

private void OnExportGridToCSV()
{


//string currentUser = WindowsIdentity.GetCurrent().Name.ToString();

//DirectorySecurity ds = Directory.GetAccessControl(Server.MapPath("~/OutputFiles/"));

//AuthorizationRuleCollection arc = ds.GetAccessRules(true, true, typeof(System.Security.Principal.NTAccount));

//string sas = WindowsIdentity.GetCurrent().Groups.ToString();
//string pUser = Page.User.Identity.Name;
//string wUser = System.Security.Principal.WindowsIdentity.GetCurrent().Name;
//string currentPrincipal = System.Threading.Thread.CurrentPrincipal.Identity.Name;



try
{
if (rowCt > 0)
{
// Create the CSV file to which grid data will be exported.

string fileName = DateTime.Now.ToShortDateString() + "_PODiscrepancyResults.csv";
fileName = fileName.Replace("/", "");
string fileNameAndPath = Server.MapPath("~/OutputFiles/") + fileName;
//StreamWriter sw = new StreamWriter(Server.MapPath("~/OutputFiles/"+fileName), false);

int iColCount = resultDT.Columns.Count;
if (File.Exists(fileNameAndPath))
{
File.Delete(fileNameAndPath);
}
StreamWriter sw = File.CreateText(fileNameAndPath);

// First we will write the headers.

for (int i = 0; i < iColCount; i++)
{
// Can pick out the specific columns. Do not write all the data that's in the GRID.not useful to user
sw.Write(resultDT.Columns[i].ColumnName);
if (i < iColCount - 1)
{
sw.Write(",");
}
}
sw.Write(sw.NewLine);
// Now write all the rows.
foreach (DataRow dr in resultDT.Rows)
{

for (int i = 0; i < iColCount; i++)
{
//pick out the specific columns. Do not write all the data that's in the GRID.not useful to user
if (!Convert.IsDBNull(dr[i]))
{
sw.Write((string)dr[i]);
}
if (i < iColCount - 1)
{
sw.Write(",");
}
}
sw.Write(sw.NewLine);
}
sw.Close();




} // if (resultDT.Rows.Count > 0)
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}//end ExportGridToCSV

}

Wyatt Wong
January 13, 2008

# re: ASP.NET 2.0 MasterPages and FindControl()

I would like to recursive Find ALL Controls instead of providing a particular control ID to find, how can I achieve this ?

Mitja Fortuna
January 24, 2008

# re: ASP.NET 2.0 MasterPages and FindControl()

Thank you so much. I've been cracking my head for days with this problem.

Rudi Jensen
February 06, 2008

# re: ASP.NET 2.0 MasterPages and FindControl()

So simple, but what a burden removed from my shoulders. THANK YOU

Anuj Saxena
February 08, 2008

# re: ASP.NET 2.0 MasterPages and FindControl()

sir ,
how to make the subdomain folder in web application by using asp.net and copy all files which are present in a particular domain.
Just example -->

www.ibloz.com website domain have some files and folder in wwwroot folder.I wanna to copy all files in this domain as a individual folder for a particular user.If a user name
is anuj then webite as a called by url www.anujibloz.com.

David
March 27, 2008

# re: ASP.NET 2.0 MasterPages and FindControl()

THanks - really useful to me after hours of trying!

Danzig
March 30, 2008

# re: ASP.NET 2.0 MasterPages and FindControl()

Thanks Rick.

I'm still amazed by the amount of time that myself and other developers waste on finding answers to issues like this in order to achieve something incredibly simple. eg. I just want to get the text value submitted in a text box.

I thought that .Net was supposed to make developer's lives easier. With classic ASP we knew that we could get the value of any form element with request.form("element_name") and it worked regardless of any template etc design.

Classic ASP: request.form("element_name")
ASP.Net: this.lblError = this.Master.FindControl("Content").FindControl("element_name") as Label;


Progress? I think not.

Rick Strahl
March 30, 2008

# re: ASP.NET 2.0 MasterPages and FindControl()

@Danzig - you can still do all the things that ASP classic did. If you don't use features like Master Pages the whole naming container issue is rarely a problem and you can still do Request.Form["element_name"]. Of course you can always do: Request.Form[element_name.UniqueId] but then if you know the control I guess you wouldn't be in this place in the first place.

If you want simple - keep it simple. Don't use master pages, don't use the high level abstractions and you get the same behavior. if you want to take advantage of the high level features then you have to play by the rules of the framework.

Saber
April 05, 2008

# re: ASP.NET 2.0 MasterPages and FindControl()

Thanks, It was what I were looking for!

GBN

Frenky B.
April 27, 2008

# re: ASP.NET 2.0 MasterPages and FindControl()

Thanx Rick and God bless you.

Fat Boy
May 13, 2008

# re: ASP.NET 2.0 MasterPages and FindControl()

What about from a
Master -> PlaceHolder -> ControlHolder -> User control -> GridView.SelectedValue ---> NULL

the funny thing is that I can see the
GridView.SelectedValue
GridView.SelectedIndex
GridView.SelectedKey.Value

from the watch panel, everything has got the value

but.... it throws NULL Object.....

btw, i was trying to do some work at Pre-Render

Momenee
May 21, 2008

# re: ASP.NET 2.0 MasterPages and FindControl()

Below is a pseudo aspx page layout, not to be taken literally.

<Content>
<ListView>
<LayoutTemplate>
<DataPager />
</LayoutTemplate>
<ItemTemplate>
<TabContainer>
<TabPanel>
<Label ID="lblHx" Text='<%# Eval("Hx")%>' />
</TabPanel>
<TabPanel>
<Label ID="lblExam" Text='<%# Eval("Exam")%>' />
</TabPanel>
...
</TabContainer>
</ItemTemplate>
<EditItemTemplate>
<TabContainer>
<TabPanel>
<TextBox ID="txtHx" Text='<%# Bind("Hx")%>' />
</TabPanel>
<Tabpanel>
<TextBox ID="txtExam" Text='<%# Bind("Exam")%>' />
</TabPanel>
...
</TabContainer>
</ListView>
<ObjectDataSource />
</Content>

The object that is passed to my update method is not picking up the values entered by the user in the page's Web controls.

Do I need to handle the Updating event of ListView and there use your FindControlRecursive method to reference the controls inside the AJAXControlToolkit.Tabcontainer control to manually fill the object being passed to my update method?

For the sake of simplicity, the following omits any reference to the object being passed and shows how to get the text from a control inside one of the tabpanels using your method. My question is, Is this the only (or best) way to get the values I need for my object, which really defeats the idea of using an object at all since you need to manually set the value of each property?

protected void lvOpenVisits_ItemUpdating(object sender, ListViewUpdateEventArgs e)
{
ListView lv = sender as ListView;
TextBox hx = FindControlRecursive(lv, "txtHx") as TextBox;
string txt = hx.Text;
}

Awadhesh
May 27, 2008

# re: ASP.NET 2.0 MasterPages and FindControl()

i have a small problem, i am using the nested master pages in my asp.net application (using VS2008 Express Edition). I want to add dynamic menu in my master page, when i add this menu in single master page and bind through the database it is work fine,but when i try in the second level master page it is not work. please help me if you have any solution.

Jonas
June 03, 2008

# re: ASP.NET 2.0 MasterPages and FindControl()

Thank you!

I used this.Page instead for a reference in my case though.

Again, thanks!

/Jonas

Ghazanfar Khan
June 27, 2008

# re: ASP.NET 2.0 MasterPages and FindControl()

Hi Rick, great article. I was doing some research on quirks associated with masterpages when using FindControl in cross-page postbacks and after reading this and a few other articles, including ASP.Net 2.0 - Master Pages: Tips, Tricks, and Traps , by Scott, I'm begining to wonder if I should even dare :P

So I started tinkering with them in a test website. And surely, in a Page_Load of page that inherited from a master file, I could reference a control using a member variable like

Label lbl1 = lblName; //lblName exists on the aspx


but in the very next line,

Label lbl2 = (Label)Page.FindControl("lblName");
would not work.

Nor did

Label lbl3 = (Label)Page.FindControl("ctl00_ContentPlaceHolder1_lblName"); 
//ctl00_ContentPlaceHolder1_lblName being the clientID of the rendered Label ctrl


Also,

Content ct = (Content)Page.FindControl("Content1"); //did not yield anything


nor using


Page.Master.FindControl instead of Page.FindControl in any of the statements above was any good.

So, I'm wondering if the solution suggested by Scott Allen

(
Rick:

Try using CodeFileBaseClass in your @ Page directive. This let's the ASP.NET code generator find those protected fields in your base class and wire them to the controls in the aspx.

)
is a conclusive solution to this problem if we declare the control names as protected fields in the base class like he suggested.

Some others have suggested using the PreviousPageType directive on your page like
<%@ PreviousPageType VirtualPath="~/Page1.aspx" %>

and exposing what you need to access from the previous page as a public property.
In my application, I have several pages that can post to an "update.aspx" page, which then uses Page.PreviousPage.FindControl to find values in hidden fields from the previous page... Any suggestions on how I would do this if I used Masterpages...?

Incase Scott is reading this, I really enjoy your articles too. Whats your take on this?
How would you guys say I can recursively go through all the content controls on a page inheriting from a master page to just see all the controls, their parents and children just for experimentation sake...to see how the master and content pages are merged together?

Thanks again guys!

Ghazanfar

Ghazanfar Khan
June 27, 2008

# re: ASP.NET 2.0 MasterPages and FindControl()

In reponse to my own post, I found that I can find the controls that are on the content page like this


protected void btnSubmit_Click(object sender, EventArgs e)
{

ContentPlaceHolder cph = (ContentPlaceHolder)Master.FindControl("ContentPlaceHolder1");
Label lbl0 = (Label)cph.FindControl("lblName");
TextBox txb1 = (TextBox)cph.FindControl("txbName");
DropDownList gen = (DropDownList)cph.FindControl("ddlGender");

lblResult.Text = lbl0.Text.ToString() + txb1.Text.ToString() + "<br>Gender: " +
gen.SelectedItem.ToString();

}

I realise that you (Rick or Scott) know this all too well, I thought I'd post for the benefit of other readers:)

Still, any suggestions on "how to think" to be able to percieve the hierarchy of the controls on the final rendered HTML..

I was also wondering, when a web request is sent to a server for a page that inherits from a master page, the server does the merge, generates the html and sends that to the clients browser, correct? Everytime this client posts back to the server, say, to do some operation on some user input on the same page, should it address the controls with their "new" IDs

eg. ConvertToInt32(ctl00_ContentPlaceHolder1_txb1.Text) +
ConvertToInt32(ctl00_ContentPlaceHolder1_txb2.Text);

or simply:

ConvertToInt32(txb1.Text) + ConvertToInt32(txb2.Text)

I realize we should never hardcode the ctl00_ContentPlaceHolder1_ part into our applications, but just wondering which of these two would be recognized? Still having a hard time grasping how the nuts & bolts of a masterpage driven page works...:(

Cm.Shafi
July 30, 2008

# re: ASP.NET 2.0 MasterPages and FindControl()

I have used following vbcode to load 5 textbox control dynamically
For i = 0 To j

Dim MyTextBox As New TextBox
MyTextBox.ID = "TextInBrief" & i
MyTextBox.TextMode = TextBoxMode.MultiLine
MyTextBox.Height = 88
MyTextBox.Width = 443
MyTextBox.Text = "TextInBrief" & i
Panel1.Controls.Add(MyTextBox)

Dim MyLiteral2 As New LiteralControl
MyLiteral2.Text = "<br/>"
Panel1.Controls.Add(MyLiteral2)
next

But when i try to retrieve the values of texboxes by clicking button1 got err:Object reference not set to an instance of an object. I have used masterpage.

button click code follows

Protected Sub Button1_Click(ByVal sender As Object, ByVal e As System.EventArgs)handles Button1.Click

Dim brf As String = ""
Dim i As Int16 = 0
For i = 0 To 4
Dim txt As TextBox = CType(Master.FindControl("ContentPlaceHolder1").FindControl("TextInBrief" & i), TextBox)
If Trim(txt.Text) <> "" Then
brf = brf & txt.Text
End If
Next
label1.text=brf
end sub


the same code i used with other my project running perfectly.
But this i don't know.
Where i made mistake? Please help me.

Dejv
August 01, 2008

# re: ASP.NET 2.0 MasterPages and FindControl()


Hello,
I used your function FindControlRecursive. :)
You saved my some time.

Bye

Romi
August 25, 2008

# re: ASP.NET 2.0 MasterPages and FindControl()

Hi Rick,

Many Thanks, FindRecursive work wonderfull. I have one litle problem with one multi UC.
MasterPage(Uc1( Uc2))

FindRecursive works fine when I search Textboxes, Dropdowns in UC1 and UC2, but I not able to found one control selected inside one "Panel" used in one UC2

UC2 ( return one ItextControl --> textControl)
 <%@ Control Language="C#" AutoEventWireup="true" CodeFile="loc3_city.ascx.cs" Inherits="loc_city" %>
<asp:TextBox ID="LinkCity" runat="server" Visible="false" width="30px"></asp:TextBox>

<asp:ScriptManagerProxy ID="ScriptManagerProxy1" runat="server">
</asp:ScriptManagerProxy>
<asp:UpdatePanel ID="UpdatePanel1" runat="server" UpdateMode="conditional">
  <ContentTemplate>
    <asp:Panel ID="Panel1" runat="server"  Width="100px" Style="Display:inline">  </asp:Panel>
  </ContentTemplate>
</asp:UpdatePanel>
.

UC1
<li>
<com:MultiCombo ID="City" runat="server" />
</li>

UC1 inside MasterPage.

The UC2 return one Panel with the Cities to be selected. I can cast directly in UC1 when I use DrpdownBox and selected item, but Panel not cast!

This is the Html of the zone generated

<div id="ctl00_ContentPlaceHolder1_controlPanel_ctl00_ctl00_editMetaFields_ctl00_City_Panel1" style="width: 100px; display: inline;">
<div>
<select name="ctl00$ContentPlaceHolder1$controlPanel$ctl00$ctl00$editMetaFields$ctl00$City$ctl02">
<option value="1" selected="selected">NY</option>
<option value="2">LA</option>
</select>
</div>
</div>

Any sugestion?

Thomas Hansen
December 04, 2008

# re: ASP.NET 2.0 MasterPages and FindControl()

Here's a much better one; http://ra-ajax.org/jquery-ish-selector-for-webcontrols.blog

It's kind of like the jQuery Selector version for WebControls on the server ... ;)

Fernando Paiva
March 27, 2009

# re: ASP.NET 2.0 MasterPages and FindControl()

Excellent ! It saved me some time trying to figure out how to access a control on my masterpage.

Chua Wen Ching
May 07, 2009

# re: ASP.NET 2.0 MasterPages and FindControl()

Save me enormous time. Thanks :)

Erik Pennings
July 23, 2009

# re: ASP.NET 2.0 MasterPages and FindControl()

thanks

LW
August 09, 2009

# re: ASP.NET 2.0 MasterPages and FindControl()

This is indeed a good help ! For about 2 days, I'm looking all answers and this finally solved my issue accessing from a Content page to a hyperlink visibility inside a LoginView of a Master page.

Ammar
August 23, 2009

# re: ASP.NET 2.0 MasterPages and FindControl()

This solution also works for getting to a control when the page has multiple master pages. I am just worried about efficiency of the solutions (its used about 2-3 times in a page load). However, with 4 master pages I fear that the code with FindControl may be hard to maintain/read in case that page structure does change? Have you come across this scenario before Rick? or what would be your recommended solution?

sanjay
October 07, 2009

# re: ASP.NET 2.0 MasterPages and FindControl()

i love u rick

Bob Avallone
October 14, 2009

# re: ASP.NET 2.0 MasterPages and FindControl()

Thanks, Rick you're a lifesaver.

jbeechii
November 15, 2009

# re: ASP.NET 2.0 MasterPages and FindControl()

Thanks, Rick - perfect for my needs!!

kzen
November 27, 2009

# re: ASP.NET 2.0 MasterPages and FindControl()

Rick, just to say thanks, this saved me a ton of hair...

Scott Hugh Alexandar Petersen
November 30, 2009

# re: ASP.NET 2.0 MasterPages and FindControl()

Werks like a charm ;)

Thanks Rick

Jan Blomquist
January 23, 2010

# re: ASP.NET 2.0 MasterPages and FindControl()

The built-in FindControl in ASP.NET is recursive already. If you pass in a UniqueID, FindControl will traverse the control tree and find your control.

If you want to get it by traversing a child collection, simply throw in a simple LINQ extension method called All that will recursively decend any Control collection and you have yourself a neat selection mechanism:

For example:
MyPanel.Controls.All().OfType<Panel>().FirstOrDefault()

Rick Strahl
January 25, 2010

# re: ASP.NET 2.0 MasterPages and FindControl()

@Jan - if you pass in the uniqueId most likely you already have a control instance, so not sure that this is all that useful. The typical scenario is that you only have the 'local' control name and need to find that in a container and for that recursion is not native.

Jan Blomquist
January 27, 2010

# re: ASP.NET 2.0 MasterPages and FindControl()

@Rick: In Ajax post/requests it's quite useful because you most likely have the full clientid/uniqueid.

I also pointed out this fact since very few (anybody?) has written anything about it. I myself discovered it while using Reflector.

Of course we agree that such a function is useful in some cases and that's why I provide the case that a useful LINQ extension is easier:

 public static IEnumerable<Control> All(this ControlCollection controls)
        {
            foreach (Control control in controls)
            {
                foreach (var grandchild in control.Controls.All())
                    yield return grandchild;
 
                yield return control;
            }
        }

Ron
February 24, 2010

# re: ASP.NET 2.0 MasterPages and FindControl()

I have what I thought was a simple issue. I have a masterpage with a container. I want to get the values of the text boxes. Simple? No not for me. The textbox name is EventTitle. I tried

String ET = Request["EventTitle"].text; (All this does is give me the value that was originally there not what it was changed to)

<asp:TextBox ID="EventLink" runat="server"></asp:TextBox>

tried this in the code behind:

string EventTitle = Request["EventTitle"]; (using this I get a null)

I tried using the FindControl but that seems a bit comberson to get a value in the code behind. Every example I find is far different from eachother. I think there is something missing.

Any thoughts?

Alex
March 20, 2010

# re: ASP.NET 2.0 MasterPages and FindControl()

Thanks for the post AND many thanks to ScottGu for the tip about the "CodeFileBaseClass" @ page attribute, had no idea about it.

Charu Ramchandani
April 12, 2010

# re: ASP.NET 2.0 MasterPages and FindControl()

Thanks a ton!!

Your blogs are really helpful. You saved me a lot of time.
Keep Writing!!! :)

Baris
May 17, 2010

# re: ASP.NET 2.0 MasterPages and FindControl()

Wonderfulll
Thank you very much Rick. I've been looking this for hours.
And it works. Thanks again :)

Raven
June 02, 2010

# re: ASP.NET 2.0 MasterPages and FindControl()

Rick -

After banging my head against the wall (literally) for 3 days, I finally came across this post and IT WORKS!!!!

Thank you so much for sharing!

raven
June 02, 2010

# re: ASP.NET 2.0 MasterPages and FindControl()

I am running into some issues and I hope you or someone out there can help me. I am trying to loop thru all the items in a datalist. The datalist is located on a web user control page and that page is located in a wizard control step. here is some of the code. My issue is that when I loop through each item in my datalist: Genredropdownlist, PublicationLabelName, and PublicationLabelId return the same data for each item in the list. The count is 12 but it returns only data for 1. Please advise on how I can fix this matter. I looked at the id's for some of the Genredropdownlist controls and here are examples: ctl00_ContentPlaceHolder1_Wizard1_UserControl1_dlPubByGenre_ctl00_ddlAddGenre,
ctl00_ContentPlaceHolder1_Wizard1_UserControl1_dlPubByGenre_ctl01_ddlAddGenre,
ctl00_ContentPlaceHolder1_Wizard1_UserControl1_dlPubByGenre_ctl02_ddlAddGenre.

When I loop through the items it only returns data for this one: "ctl00_ContentPlaceHolder1_Wizard1_UserControl1_dlPubByGenre_ctl00_ddlAddGenre"

Please any help would be much appreciated.


pubgenredatalist = Me.UserControl1.FindControl("dlPubByGenre")
Dim count As Integer = pubgenredatalist.Items.Count
Dim i As Integer
Dim dlitem As DataListItem
Dim myTable As New DataTable
myTable.Columns.Add("Pub Id", Type.GetType("System.String"))
myTable.Columns.Add("Pub Name", Type.GetType("System.String"))
myTable.Columns.Add("Genre Id", Type.GetType("System.String"))
myTable.Columns.Add("Genre Name", Type.GetType("System.String"))


For Each dlitem In pubgenredatalist.Items
Dim Genredropdownlist As DropDownList = TryCast(wwWebUtils.FindControlRecursive(pubgenredatalist, "ddlAddGenre"), DropDownList)
Dim PublicationLabelId As Label = TryCast(wwWebUtils.FindControlRecursive(pubgenredatalist, "lblpubid"), Label)
Dim PublicationLabelName As Label = TryCast(wwWebUtils.FindControlRecursive(pubgenredatalist, "lblpubname"), Label)
Dim myrow As DataRow
myrow = myTable.NewRow
myrow("Pub Id") = CInt(PublicationLabelId.Text)
myrow("Pub Name") = PublicationLabelName.Text
myrow("Genre Id") = CInt(Genredropdownlist.SelectedValue)
myrow("Genre Name") = Genredropdownlist.SelectedItem.Text
Next

James
October 06, 2010

# re: ASP.NET 2.0 MasterPages and FindControl()

Thanks for the example. I had to tweak it a bit to work when a given user control is used more than once on a page, but this was a good place to start from. Appreciate it.

Brent G
November 19, 2010

# re: ASP.NET 2.0 MasterPages and FindControl()

I finally had it... I've decided to make this site my default site. For whatever reason I always seem to gravitate back to this site for solutions. Rick, you are the man!

Brent G
November 19, 2010

# re: ASP.NET 2.0 MasterPages and FindControl()

I finally had it... I've decided to make this site my default site. For whatever reason I always seem to gravitate back to this site for solutions. Rick, you are the man!

novice
January 16, 2011

# re: ASP.NET 2.0 MasterPages and FindControl()

I have a master page MasterMain and a content page MyTest.
Inside the content page, MyTest, I have a text box control txtTestControl.
In the MyTest.aspx.cs, I am trying to assign a string value to the text property of the text box control.
Depending on what value is populated in the textbox, in the MyTest.aspx page, I am trying to
extract the value using the document.getElementByID().value in a java script function.

My problem is, if I hardcode the value in the Text Property of the textbox, I can extract it from MyTest.aspx page

But if I assign value like txtTestControl.Text = "abc" in the page load, it returns blank or null.

How do I assign value to the text property of a textbox control inside a content page?

john
January 20, 2011

# re: ASP.NET 2.0 MasterPages and FindControl()

Thanks for the info, I've been banging my head against the wall for this exact reason for a while now. It never occurred to me that the master page may be the issue. Thanks!

Mark
April 05, 2011

# re: ASP.NET 2.0 MasterPages and FindControl()

Rick, you are a guru - your solution just saved my bacon! Keep up the GREAT work!

husain
April 14, 2011

# re: ASP.NET 2.0 MasterPages and FindControl()

awesome Rick...you saved tons of my time and energy :)
Thanks a lot...and keep up the good work....

Harvey Triana
August 06, 2011

# re: ASP.NET 2.0 MasterPages and FindControl()

Hello ... going to the initial question.

A good approach to solving the performance:

MasterPage:
...
<asp:ContentPlaceHolder id="cphMain" runat="server" />
...
Code of MasterPage:
...
public Control GetControl(string ID)
{
return cphMain.FindControl(ID);
}
....
A Page:
...
<%@ MasterType VirtualPath="~/MasterPage.master"%>
...
Code of Page:
...
this.lblError = Master.GetControl("lblError") as Label;
// insted of less performance
this.lblError = this.Master.FindControl("cphMain").FindControl("lblError") as Label;

dotNetFollower
September 29, 2011

# re: ASP.NET 2.0 MasterPages and FindControl()

Nice article! My own FindControlRecursive helped me out many times, especially when I deal with MasterPages. For example, one of the usage of FindControlRecursive is shown in my post here - http://dotnetfollower.com/wordpress/2010/12/sharepoint-add-onchange-attribute-to-dropdownchoicefield/.
Thank you!

Mark P
February 25, 2012

# re: ASP.NET 2.0 MasterPages and FindControl()

After days of headaches trying to get a value of a specified field in a gridview row, I read through Scott's article http://www.asp.net/web-forms/tutorials/master-pages/control-id-naming-in-content-pages-cs which then led me to here. It appears Scott's resolution was exactly what i needed. (using the PageExtensionMethods). Before I found this I was getting the dreaded "object reference not set to an instance.." message. I'm somewhat of a Novice to Asp.Net and C# so I'm probably missing something obvious.

Summary: I am using a basically Masterpage / Content Page where I have a gridview bound to a sql table containing some rows of data firstname, lastname, state, etc. I enabled the option to delete, select, edit a row. Converted the CommandField to a TemplateFields.

When I click the Delete button for a specified row I am first firing RowDeleting method so I can grab the firstName value from the selected row and displaying the value to a label control.

protected void GridView1_RowDeleting(object sender, GridViewDeleteEventArgs e)
{
Label FirstName = (Label)Page.FindControlRecursive("Label1");
Label3.Text = FirstName.Text;
}

The correct record deletes but the FirstName Label from the RowDeleting method always returns the Firstname for the first record in the table. Why isn't (Label)Page.FindControlRecursive("Label1") retrieving the Firstname value for the row I clicked the delete button from?

During troubleshooting I set up this method

protected void GridView1_SelectedIndexChanged(object sender, EventArgs e)
{
Label FirstName = (Label)Page.FindControlRecursive("Label1");
Label2.Text = FirstName.Text;
}

Anytime I would click the Select button next to any row in my GV I would get the same result as above. (The FirstName) of the First Row.)

What am I missing or not understanding here?

Ronen Festinger
July 08, 2012

# re: ASP.NET 2.0 MasterPages and FindControl()

You can simply do now:
this.ContentPlaceHolderGridView.FindControl("GridViewManageList") as GridView;

instead of going to the master and search for the content, you can access it directly.

Nick
May 18, 2013

# re: ASP.NET 2.0 MasterPages and FindControl()

Scott Gu says: "One thing we worried about what the performance impact of people mis-using it -- since doing deep walks of the entire control tree lots of time can really slow things down if you don't know what you are doing. "

If anyone was really concerned about performance they wouldn't be using Webforms.

Rick Strahl
May 18, 2013

# re: ASP.NET 2.0 MasterPages and FindControl()

@Nick - that depends. WebForms is amongst the most optimized parts of ASP.NET. If you build tight WebForms (ie. little to no reliance on ViewState) those apps will run faster than MVC apps for example. Talking about slow tech, MVC uses so much dynamic and runtime reflection for inference of types etc. that it has quite a bit of overhead.

All in all the perf difference between the various ASP.NET platforms is relatively small either way though although I totally agree - if you use WebForms the way that most tutorials teach you and using massive third party controls you're quite likely to build a dog of an application. Same is true of other platforms though.

In short, don't spout unsubstantiated crap like that that is totally subjective and dependent on what you actually do in the specific application.

Luis Damas
May 23, 2013

# re: ASP.NET 2.0 MasterPages and FindControl()

Public Shared Function FindControlRecursive(Root As Control, Id As String) As Control
  If Not (Root.ID Is Nothing) AndAlso Root.ID.ToUpper = Id.ToUpper Then Return Root

  For Each Ctl As Control In Root.Controls
  Dim FoundCtl As Control = FindControlRecursive(Ctl, Id)
  If Not (FoundCtl Is Nothing) Then Return FoundCtl
  Next
  Return Nothing
End Function

West Wind  © Rick Strahl, West Wind Technologies, 2005 - 2024