AlexC
AlexC

Reputation: 9661

C#, FindControl

I'm sorry, but I can't understand why this doesn't work. After compile, I receive a "Null reference exception". Please help.

public partial class labs_test : System.Web.UI.Page
{
    protected void Button1_Click(object sender, EventArgs e)
    {
        if (TextBox1.Text != "")
        {
            Label Label1 = (Label)Master.FindControl("Label1");
            Label1.Text = "<b>The text you entered was: " + TextBox1.Text + ".</b>";
        }
    }

    protected void DropDownList1_SelectedIndexChanged(object sender, EventArgs e)
    {
        Label Label1 = (Label)Master.FindControl("Label1");
        Label1.Text = "<b>You chose <u>" + DropDownList1.SelectedValue + "</u> from the dropdown menu.</b>";
    }
}

and UI:

<%@ Page Language="C#" MasterPageFile="~/MasterPage.master" AutoEventWireup="true" CodeFile="test.aspx.cs" Inherits="labs_test" Title="Untitled Page" %>

<asp:Content ID="Content1" ContentPlaceHolderID="head" Runat="Server">
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="ContentPlaceHolder1" Runat="Server">
Type in text and then click button to display text in a Label that is in the MasterPage.<br />
This is done using FindControl.<br />
<asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
<asp:Button ID="Button1" runat="server" OnClick="Button1_Click" Text="Submit" /><br />
<br />
Choose an item from the below list and it will be displayed in the Label that is
in the MasterPage.<br />
This is done using FindControl.<br />
<asp:DropDownList ID="DropDownList1" runat="server" AutoPostBack="True" OnSelectedIndexChanged="DropDownList1_SelectedIndexChanged">
<asp:ListItem>Item 1</asp:ListItem>
<asp:ListItem>Item 2</asp:ListItem>
<asp:ListItem>Item 3</asp:ListItem>
</asp:DropDownList>
<asp:Label ID="Label1" runat="server" Text="Label"></asp:Label>    
</asp:Content>

Upvotes: 9

Views: 29903

Answers (3)

Mattio
Mattio

Reputation: 2032

Courtesy of Mr. Atwood himself, here's a recursive version of the method. I would also recommend testing for null on the control and I included how you can change the code to do that as well.

protected void Button1_Click(object sender, EventArgs e)
{
    if (TextBox1.Text != "")
    {
        Label Label1 = FindControlRecursive(Page, "Label1") as Label;
        if(Label1 != null)
            Label1.Text = "<b>The text you entered was: " + TextBox1.Text + ".</b>";
    }
}

protected void DropDownList1_SelectedIndexChanged(object sender, EventArgs e)
{
    Label Label1 = FindControlRecursive(Page, "Label1") as Label;
    if (Label1 != null)
        Label1.Text = "<b>You chose <u>" + DropDownList1.SelectedValue + "</u> from the dropdown menu.</b>";
}

private Control FindControlRecursive(Control root, string id)
{
    if (root.ID == id) return root;
    foreach (Control c in root.Controls)
    {
        Control t = FindControlRecursive(c, id);
        if (t != null) return t;
    }
    return null;
}

Upvotes: 22

Rex M
Rex M

Reputation: 144182

FindControl only searches in the immediate children (technically to the next NamingContainer), not the entire control tree. Since Label1 is not an immediate child of Master, Master.FindControl won't locate it. Instead, you either need to do FindControl on the immediate parent control, or do a recursive control search:

private Control FindControlRecursive(Control ctrl, string id)
{
    if(ctrl.ID == id)
    {
        return ctrl;
    }
    foreach (Control child in ctrl.Controls) 
    { 
        Control t = FindControlRecursive(child, id); 
        if (t != null) 
        { 
            return t; 
        } 
    } 
    return null;
}

(Note this is convenient as an extension method).

Upvotes: 2

CRice
CRice

Reputation: 12567

When Label1 exists on the master page:

How about telling the content page where your master page is

<%@ MasterType VirtualPath="~/MasterPages/PublicUI.Master" %>

Then making a method in the master like

public void SetMessage(string message)
{
    Label1.Text = message;
}

And call it in page's code behind.

Master.SetMessage("<b>You chose <u>" + DropDownList1.SelectedValue + "</u> from the dropdown menu.</b>");

When Label1 exists on the content page

If it is simply on the same page, just call Label1.Text = someString; or if you for some reason need to use FindControl, change your Master.FindControl to FindControl

Upvotes: 4

Related Questions