问题
I have server controls such as a popup with a gridview inside template fields in another gridview:
<asp:TemplateField HeaderText="Actions">
<ItemTemplate>
<asp:Button ID="viewHoursButton" runat="server" Text="View Hours" OnClick="viewHoursButton_OnClick" />
<ajaxToolkit:ModalPopupExtender ID="viewHoursPopup" runat="server"
TargetControlID="viewHoursButton"
PopupControlID="viewHoursPanel"
CancelControlID="closeInfoPanelButton2"
DropShadow="true">
</ajaxToolkit:ModalPopupExtender>
<asp:Panel ID="viewHoursPanel" runat="server" CssClass="infoPanel">
<asp:Button ID="closeInfoPanelButton2" runat="server" Text="X" CssClass="closeInfoPanelButton" />
<asp:Label ID="viewHoursLabel" runat="server" Text="Label"></asp:Label>
<asp:GridView ID="viewHoursGridView" runat="server" AllowPaging="True" AutoGenerateColumns="False"
DataSourceID="SqlDataSource6" DataKeyNames="NonScrumStoryId,PK_DailyTaskHours"
BackColor="#DEBA84" BorderColor="#DEBA84" BorderStyle="None" BorderWidth="1px"
CellPadding="3" CellSpacing="2" Width="94%" OnRowDeleting="viewHoursGridView_OnRowDeleting"
OnRowDataBound="viewHoursGridView_OnRowDataBound" CssClass="centerGridView">
<Columns>
<asp:BoundField DataField="ActivityDate" HeaderText="Activity Date" SortExpression="ActivityDate"
DataFormatString="{0:MM/dd/yyyy}" />
<asp:BoundField DataField="Hours" HeaderText="Hours" SortExpression="Hours" />
<asp:BoundField DataField="Notes" HeaderText="Notes" SortExpression="Notes" />
<asp:BoundField DataField="CreateDate" HeaderText="Created Date" SortExpression="CreateDate"
Visible="false" />
<asp:CommandField ShowDeleteButton="True" />
</Columns>
<FooterStyle BackColor="#F7DFB5" ForeColor="#8C4510" />
<HeaderStyle BackColor="#7fc041" Font-Bold="True" ForeColor="White" />
<PagerStyle ForeColor="#8C4510" HorizontalAlign="Center" />
<RowStyle BackColor="#FFF7E7" ForeColor="#8C4510" />
<SortedAscendingCellStyle BackColor="#FFF1D4" />
<SortedAscendingHeaderStyle BackColor="#B95C30" />
<SortedDescendingCellStyle BackColor="#F1E5CE" />
<SortedDescendingHeaderStyle BackColor="#93451F" />
</asp:GridView>
<asp:SqlDataSource ID="SqlDataSource6" runat="server" ConnectionString="<%$ ConnectionStrings:ApplicationServices %>"
SelectCommand="
SELECT [DailyTaskHours].[PK_DailyTaskHours]
,[DailyTaskHours].[NonScrumStoryId]
,[DailyTaskHours].[Hours]
,[DailyTaskHours].[Notes]
,[DailyTaskHours].[ActivityDate]
,[DailyTaskHours].[CreateDate]
FROM [NonScrumStory]
,[DailyTaskHours]
WHERE [DailyTaskHours].[NonScrumStoryId] = @nonScrumStoryId
AND [NonScrumStory].[PK_NonScrumStory] = @nonScrumStoryId
ORDER BY [ActivityDate] DESC
"
DeleteCommand="
DELETE
FROM [DailyTaskHours]
WHERE ([PK_DailyTaskHours] = @setDailyPKDeleteParam)
">
<SelectParameters>
<asp:QueryStringParameter Name="nonScrumStoryId" Type="String" />
</SelectParameters>
<DeleteParameters>
<asp:QueryStringParameter Name="setDailyPKDeleteParam" Type="Int32" />
</DeleteParameters>
</asp:SqlDataSource>
</asp:Panel>
<asp:Button ID="addHoursButton" runat="server" Text="Add Hours" OnClick="addHoursButton_OnClick" />
<asp:Button ID="editButton" runat="server" Text="Edit" OnClick="editButton_OnClick" />
<asp:Button ID="deleteButton" runat="server" Text="Delete" OnClick="deleteButton_OnClick" />
</ItemTemplate>
</asp:TemplateField>
I cant move them out of the gridview because it is necessary for the call to the popup to work correctly.
However my code behind is not recognizing some of the ID's within the ItemTemplate:
protected void viewHoursButton_OnClick(object sender, EventArgs e)
{
viewHoursPopup.Show();
viewHoursGridView.DataBind();
}
For example, the _OnClick method work even though the button is inside the ItemTemplate but the two method calls are not recognized:
How do I fix this issue?
回答1:
Use the FindControl()
method, but cast them to the more specific type you are using in the ItemTemplate
declaration of your markup, like this:
protected void viewHoursButton_OnClick(object sender, EventArgs e)
{
var viewHoursPopup = parentGridView.FindControl("viewHoursPopup") as ModalPopupExtender;
var viewHoursGridView = parentGridView.FindControl("viewHoursGridView") as GridView;
if (viewHoursPopup != null && viewHoursGriView != null)
{
viewHoursPopup.Show();
viewHoursGridView.DataBind();
}
}
Note: FindControl()
returns a Control
, which is too general of an object to call the .Show()
method. The as
operator will return null
if the cast cannot be successfully performed, so the check for null
later will catch that scenario.
回答2:
protected void viewHoursButton_OnClick(object sender, EventArgs e)
{
var viewHoursPopup = parentGridView.FindControl("viewHoursPopup")
as WebControl;
var viewHoursGridView = parentGridView.FindControl("viewHoursGridView");
if (viewHoursPopup != null && viewHoursGriView != null)
{
viewHoursPopup.Show();
viewHoursGridView.DataBind();
}
}
...or...
protected void viewHoursButton_OnClick(object sender, EventArgs e)
{
var viewHoursButton = (Button)sender;
var viewHoursPopup = viewHoursButton.Parent.FindControl("viewHoursPopup")
as WebControl;
var viewHoursGridView = viewHoursButton.Parent.FindControl("viewHoursGridView");
if (viewHoursPopup != null && viewHoursGriView != null)
{
viewHoursPopup.Show();
viewHoursGridView.DataBind();
}
}
Why?
ItemTemplates, RowTemplates, EditTemplates, etc, are all nested in what webforms calls NamingContainers. You cannot access these controls because they are injected dynamically at runtime, their control ID's are not automatically mapped by the codebehind's partial auto-generated class.
There are 2 solutions:
Wrap the content of your Template into a UserControl. That UserControl's codebehind will have compile-time access to any controls that are not further nested into other Templates. To enable interaction between the UserControl and the parent Template that contains it, expose events and public properties on the UserControl
Use .FindControl(string controlID) to "search" the containing control's current Templates to find the control you are looking for. Just be sure to check them against null before trying to invoke anything on them, and that they are cast to the appropriate type based on what methods you intend to invoke on them.
来源:https://stackoverflow.com/questions/19839761/controls-in-itemtemplate-cant-be-called-in-code-behind