Reputation: 1605
I have a repeater that lists customer items, one of which is a button for more information. When the user clicks that button, a user control appears immediately below it. I'd like for the user control to then close when the button is clicked again. I initially toggled visibility server-side, but I now can't use this because the user control needs to be loaded on the button click due to parameters that need to bepassed through. I also can't used show and hide by jquery because that would involve downloading all the data first for the whole page which could make the page too cumbersome.
So currently in each repeater I have a linkbutton with command arguments and an OnCommand event which fires this event:
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);
}
}
}
}
My plan for the toggle was that if the PolicyDocuments control was null, then load the control, and if not then remove the control, but it always came back null. It did load the control correctly though.
Here is the section of the repeater:
<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>
I've had a look around for people who have had similar problems, and a common answer is that you need to load controls in the Page_Init event. Does that mean that this way won't work? Any ideas for an alternative if this is the case?
Many thanks
Upvotes: 1
Views: 1846
Reputation: 28345
I dont' understand, why you can't add the PolicyDocuments
with visible = false
and no datasource instead of Placeholder
, like that:
<uc:PolicyDocuments ID="uxPolicyDocuments" runat="server" Visible="false"></asp:PolicyDocuments>
and during the command use such code:
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;
}
}
In this case you don't need to use some hacks in Init
event of the page.
Anyway, you always can use the .Controls.OfType<PolicyDocuments>()
extension method to get all the user controls you need.
Upvotes: 1
Reputation: 7846
Every time your page is loaded (either initially, or via PostBack) the Control Tree needs to be re-created.
The controls declared in the ASPX part of your page are added by the framework (kind of), but any controls that you add "dynamically" need to be placed back in the control tree too. If they aren't then, as you've disovered, they simply can't be found again.
Complex controls, like the datagridview, rebuild their control tree by storing (a huge amount of) data in the ViewState.
It might be simpler, rather than have your page add/remove items from a PlaceHolder
, to create a user control that you can and hide, and load it's data the first time its shown. This also helps your controls and pages adhere to the Single Repsonsibility Principal
Upvotes: 3