FindControl找不到我动态添加的控件

时间:2011-06-17 10:36:11

标签: c# asp.net

我有一个列出客户项目的转发器,其中一个是一个按钮以获取更多信息。当用户单击该按钮时,用户控件将立即显示在其下方。我希望用户控件在再次单击按钮时关闭。我最初切换了服务器端的可见性,但我现在无法使用它,因为由于需要通过的参数,需要在按钮单击时加载用户控件。我也不能使用jquery显示和隐藏,因为这将涉及首先下载整个页面的所有数据,这可能会使页面太麻烦。

所以目前在每个转发器中我都有一个带有命令参数的链接按钮和一个触发此事件的OnCommand事件:

protected void uxPolicyDocsButton_Command(object sender, CommandEventArgs e)
    {
        //Find Policy Summary control within repeater item in order to toggle visibility

        LinkButton button = sender as LinkButton;
        if (button != null)
        {
            RepeaterItem ri = button.Parent as RepeaterItem;

            if (ri != null)
            {
                PlaceHolder policySummaryPlaceHolder = (PlaceHolder)ri.FindControl("uxPolicySummaryPlaceHolder");                    
                Control policyDocuments = (Control)PolicySummaryPlaceHolder.FindControl("uxPolicyDocumentsControl");


                foreach (Control c in policySummaryPlaceHolder.Controls)
                {
                    //FindControl action goes in here.  Have stepped through though and it doesn't appear
                }

                if (policyDocuments != null)
                {
                    policySummaryPlaceHolder.Controls.Remove(policyDocuments);
                }
                else
                {
                    policyDocuments uxPolicyDocumentsControl = (PolicyDocuments)LoadControl("~/Controls/Home/PolicyDocuments.ascx");
                    uxPolicyDocumentsControl.PolicyNumber = button.CommandArgument;
                    policySummaryPlaceHolder.Controls.Add(uxPolicyDocumentsControl);
                }
            }
        }
    }

我的切换计划是,如果PolicyDocuments控件为null,则加载控件,如果没有则删除控件,但它总是返回null。它确实正确地加载了控件。

以下是转发器的部分:

<ItemTemplate>
                    <tr>
                        <td>
                            <%#Eval("StartDate","{0:d}")%>
                        </td>
                        <td class="center-cell-ctrl">
                            Postcode:<br />
                            <%#Eval("Postcode")%>
                        </td>
                        <td id='<%#Eval("PolicyNumber")%>' class="button-cell">                                
                            <asp:LinkButton ID="uxPolicyDocsButton" CommandName="PolicyNumber" CommandArgument='<%#Eval("PolicyNumber")%>' OnCommand="uxPolicyDocsButton_Command"  runat="server" Visible="false">Policy<br />Documents</asp:LinkButton>
                        </td>
                    </tr>
                    <asp:PlaceHolder ID="uxPolicySummaryPlaceHolder" runat="server"></asp:PlaceHolder>
                    <asp:PlaceHolder ID="uxPolicyDocumentsPlaceHolder" runat="server"></asp:PlaceHolder>

        </ItemTemplate>

我已经浏览过遇到类似问题的人,而且常见的答案是你需要在Page_Init事件中加载控件。这是否意味着这种方式不起作用?如果是这种情况,有任何想法吗?

非常感谢

2 个答案:

答案 0 :(得分:3)

每次加载页面(最初或通过PostBack)时,都需要重新创建控制树。

在页面的ASPX部分中声明的控件是由框架(类型)添加的,但是“动态”添加的任何控件也需要放回到控件树中。如果他们不是,那么你已经发现,他们就再也找不到了。

复杂控件(如datagridview)通过在ViewState中存储(大量)数据来重建其控制树。

它可能更简单,而不是让您的页面添加/删除PlaceHolder中的项目,以创建可以隐藏的用户控件,并在第一次显示时加载它的数据。这也有助于您的控件和页面符合Single Repsonsibility Principal

答案 1 :(得分:1)

我不明白,为什么你不能添加PolicyDocuments visible = false而不添加数据源而不是Placeholder,如下所示:

<uc:PolicyDocuments ID="uxPolicyDocuments" runat="server" Visible="false"></asp:PolicyDocuments>

并在命令期间使用此类代码:

        if (ri != null)
        {
            var policyDocuments = ri.Controls.OfType<PolicyDocuments>().FirstOrDefault();
            if (policyDocuments == null)
                return;

            if (policyDocuments.Visible)
            {
                policyDocuments.Visible = false;
            }
            else
            {
                policyDocuments.PolicyNumber = button.CommandArgument;
                policyDocuments.Visible = true;
            }
        }

在这种情况下,您无需在页面的Init事件中使用某些黑客。 无论如何,您始终可以使用.Controls.OfType<PolicyDocuments>()扩展方法来获取所需的所有用户控件。