在母版页里使用FindControl的困惑


 

在母版里使用FindControl

   通常在内容页里会使用不止一个Content控件,在这种情况下. 我们可能需要让不同Content的里的控件进行通信,本节就来介绍这些问题。

例如下面是一个简单的母版simple.master

<%@ Master Language="C#" AutoEventWireup="true" CodeFile="simple.master.cs" Inherits="simple" %>

 

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

 

<html xmlns="http://www.w3.org/1999/xhtml" >

<head runat="server">

    <title>Untitled Page</title>

</head>

<body>

    <form id="form1" runat="server">

    <div>

        <asp:contentplaceholder id="ContentUp" runat="server">

        </asp:contentplaceholder>

           <asp:contentplaceholder id="ContentDown" runat="server">

        </asp:contentplaceholder>

    </div>

    </form>

</body>

</html>

 

在这个母版里使用了两个ContentPlageHolder控件,其ID分别为ContentUpContentDown,这里的名称表示将来我想将内容页分为上半部和下半部。

 

为了使用该母版,我建立了一个 内容页 FindControl_Masterpage.aspx,代码如下:

<%@ Page Language="C#"  Trace="true" MasterPageFile="~/simple.master" AutoEventWireup="true" CodeFile="FindControl_Masterpage.aspx.cs" Inherits="FindControl_Masterpage" Title="Untitled Page" %>

<asp:Content ID="Content1" ContentPlaceHolderID="ContentUp" Runat="Server">

<asp:Label runat="server" ID="lblInfo"></asp:Label>

</asp:Content>

<asp:Content ID="Content2" ContentPlaceHolderID="ContentDown" Runat="Server">

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

<asp:Button ID="btnSubmit" runat="server" Text="Submit" OnClick="btnSubmit_Click" ></asp:Button>

</asp:Content>

 

  这里的内容页很简单,在ContentUp里放置了一个IDlblInfo的标签,在ContentDown里放置了一个IDtxtInfo的文本框和IDbtnSubmit的按钮。

现在我想在文本框里输入文本,然后单击按钮,让Label标签显示输入的文本,所以在btnSubmit_Click的事件里输入代码如下:

protected void btnSubmit_Click(object sender, EventArgs e)

    {

      lblInfo.Text = txtInfo.Text;

     }

 上面的方法在内容页运行时工作的很好,但是有时候我们的要求可能并不是这么简单。比方说,我在Content1中定义有一个ObjectDataSource,在Content2中定义有一个TextBox,我想将ObjectDataSourceSelectParameter设定到TextBox上,那么此时就需要获取TextBox控件。您可能很容易编写如下代码:

protected void btnSubmit_Click(object sender, EventArgs e)

    {

    Label lblLabel = (Label)Page.FindControl("lblInfo");

      lblLabel.Text = txtInfo.Text;

     }

  我么的想法是利用PageFindControl控件查扎IDlblInfo的标签,然后设置其Text属性。然而很遗憾,如果您使用上面代码,在运行时将出现如下的提示错误: 

 

image1.png 

 

  也许有人认为这是因为LabelButton控件在不同的Content所致,但是虽然TextBoxButton在同一个Content,那么你编写如下代码同样会出现上面的问题:

protected void btnSubmit_Click(object sender, EventArgs e)

    {

   TextBox txtTextBox = (TextBox)Page.FindControl("txtInfo");

        txtTextBox.Text = "helloworld";

     }

  那么为什么会出现上面错误呢?前面介绍了母版页和内容页运行原理时曾经说过,用户最终请求的是内容页,母版页和内容页在之中处理请求时,母版页会融合到内容页里,我们可以利用跟踪技术查看这种结果,此时在内容页里添加Trace属性如下:

<%@ Page Language="C#"  Trace="true" … …%>

  这样在运行FindControl_MasterPage.aspx时,我们可以看到下面的跟踪效果

 

 

image003.png 

 

从图中可以看到,在页面Page控件树中,ContentUpContentDown直接在Page的控件树下,而LabelTextBoxButton又分别在ContentUpContentDown下,那么为什么FindControl找不到LabelTextBoxButton呢?

 这时,我们需要重新查看一下FindControl的定义,MSDN给出的解释如下:在页命名容器中搜索带指定标识符的服务器控件,但是请注意其备注的说明:

FindControl 方法只搜索页的直接或顶级容器;它不在页所包含的命名容器中递归搜索控件。

也就是FindControl可以找到ContentUpContentDown但是找不到LabelTextButton。如果更显示的表示如下图

FindControl不会在ContentUp/ContentDown查找其子控件,这就是为什么会出现上面错误的原因。

 

 

image005.png 

当然,这里的讨论并不完全准确,如果您仔细查看页面跟踪结果可以发现ContentUpContentDown应该算是aspnetForm的子控件,但是为什么它就可以查找aspnetForm下的子控件呢?

这里设计到控件的定义,事实上FindControl只查找未实现INamingContainer 接口的控件。而aspnetForm则未实现InamingContainer接口,就是这个原因。(判断一个控件是否实现InamingContainer接口简单的说就是在页面上能否重复使用,例如TextBox实现了InamingContainer结果,那么在一个Web页面上如下的代码是正确的

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

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

Form未实现,所以如果你在一个Web页面上同时使用了两个Form控件,如下

<form id="form1" runat="server"></form>

<form id="form2" runat="server"></form>

则这种写法是错误的。

 

既然FindControl可以在控件内部嵌套搜索,所以我们就很容易获取TextBoxLabelButton,如下:

获取

  protected void btnSubmit_Click(object sender, EventArgs e)

    {

        ContentPlaceHolder cphUp;

        Label lblLabel;

        cphUp = (ContentPlaceHolder)Master.FindControl("ContentUp");

        lblLabel = (Label)cphUp.FindControl("lblInfo");

        ContentPlaceHolder cphDown;

        cphDown=(ContentPlaceHolder)Master.FindControl("ContentDown");

        TextBox txtTextBox;

        Button btnButton;

        txtTextBox = (TextBox)cphDown.FindControl("txtInfo");

        if (cphUp != null && cphDown!=null)

        {

          if (lblLabel != null && txtTextBox != null)

                lblLabel.Text = txtTextBox.Text;

        }

     

    }

这样就可以实现在内容页上获取控件通信了。

image007.png

posted @ 2006-06-22 10:05  启明星工作室  阅读(3255)  评论(7编辑  收藏  举报