我有一个嵌套网格,可以在FooterControl中添加一行。我希望能够在用户单击“添加”按钮时验证数据。 我在后面的代码中的RowDataBound方法中添加RequiredFieldValidation。 如果此验证不在此方法中,则一切正常。但添加验证会产生错误 - 它无法找到ControlToValidate引用的ControlId。
如果有人能看到这个,看看我哪里出错了,我会很感激... 这是嵌套网格标记:
<div id="div<%# Eval("GroupID") %>" style="display:none">
<asp:GridView ID="GroupMemberGridView" runat="server" AutoGenerateColumns="false" OnRowDeleting="GroupMemberGridView_RowDeleting"
OnRowCommand="GroupMemberGridView_RowCommand" CssClass="grid" ShowFooter="true">
<Columns>
<asp:TemplateField HeaderText="MemberID">
<ItemTemplate>
<asp:Label ID="mggvLblMemberID" runat="server" Text='<%# Bind("MemberID") %>'></asp:Label>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Member Name" ItemStyle-Wrap="false">
<ItemTemplate>
<asp:Label ID="mggvLblMemberName" runat="server" Text='<%# Bind("MemberName") %>'></asp:Label>
</ItemTemplate>
<FooterTemplate>
<asp:DropDownList ID="mggvDDLMemberName" runat="server"
class="chosen-single" data-placeholder="Choose member…">
</asp:DropDownList>
</FooterTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Active Device(s)">
<ItemTemplate>
<asp:Label ID="mggvLblActiveDevice" runat="server" Text='<%# (Boolean.Parse(Eval("ActiveDevice").ToString())) ? "Yes" : "No" %>'></asp:Label>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Action" ItemStyle-Wrap="false" ItemStyle-HorizontalAlign="Center">
<ItemTemplate>
<asp:Button ID="mggvDeleteButton" runat="server" CausesValidation="False" CommandName="Delete"
Text="Delete" CssClass="gridActionbutton" OnClientClick="return confirm('Are you sure you want to delete this Group Member?')" >
</asp:Button>
</ItemTemplate>
<FooterTemplate>
<asp:Button ID="mggvAddButton" runat="server" CommandName="Add" Text="Add Member" Width="90%" ClientIDMode="Static"
CssClass="gridActionbutton" CausesValidation="true" OnClientClick="return Validate(this);" >
</asp:Button>
</FooterTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
</div>
这是创建验证
的RowDataBound事件if (e.Row.RowType == DataControlRowType.DataRow)
{
int tiGroupID = Convert.ToInt32(UserGroupGridView.DataKeys[e.Row.RowIndex].Value.ToString());
GridView tgvGroupMember = (GridView)e.Row.FindControl("GroupMemberGridView");
populateGroupMemberGrid(tgvGroupMember, tiGroupID);
//Get the Footer controls that have the new entry data
Control tFooterControls = CommonMethods.getFooterControls(tgvGroupMember);
DropDownList tddlRecipientNames = tFooterControls.FindControl("mggvDDLMemberName") as DropDownList;
m_strXmlTableData = m_pagingClient.GetAllPossibleGroupMembers(m_strUserID, tiGroupID);
DataTable tdtAllGroupMembers = CommonMethods.ParseXML(m_strXmlTableData);
tddlRecipientNames.DataSource = tdtAllGroupMembers;
tddlRecipientNames.DataTextField = tdtAllGroupMembers.Columns["MemberName"].ToString();
tddlRecipientNames.DataValueField = tdtAllGroupMembers.Columns["MemberID"].ToString();
tddlRecipientNames.DataBind();
tddlRecipientNames.Items.Insert(0, new ListItem("", "0"));
RequiredFieldValidator validator = new RequiredFieldValidator();
validator.ID = "ReqValueDDLMember_" + tiGroupID.ToString();
string id = ((DropDownList)tFooterControls.FindControl("mggvDDLMemberName")).UniqueID;
validator.ControlToValidate = ((DropDownList) tFooterControls.FindControl("mggvDDLMemberName")).UniqueID;
validator.EnableClientScript = true;
validator.ErrorMessage = "Selection required.";
validator.CssClass = "message-error-dropdown";
validator.ValidationGroup = "DDLVal_" + tiGroupID.ToString();
tgvGroupMember.Controls.Add(validator);
Button tbtnAdd = tFooterControls.FindControl("mggvAddButton") as Button;
tbtnAdd.ValidationGroup = "DDLVal_" + tiGroupID.ToString();
}
感谢。
更新 这是一个使用Master.Pages的ASP.NET Web应用程序。最初,我使用.ID并得到了同样的错误。我认为这是因为ID不是唯一的,因为有几个嵌套网格。但是,使用UniqueId标识父网格中的特定嵌套网格。但我得到同样的错误。
如果我在标记中创建验证器,则验证仅适用于第一个嵌套网格。
为什么不能找到控件?
似乎我已尝试将ControlToValidate设置为特定于DropDown控件的唯一ID。
我认为我的问题是控件ID必须是唯一的。这是一个带有Master.Pages的嵌套网格标记,在嵌套网格中为FooterControl指定ID,如'mggvDDLMember',生成ID为'ct100$MainContent$UserGroupGridView$GroupMemberGridView$.....$mggvDDLMemberName'.
在代码中设置ID,如下所示:
ControlToValidate = 'mggvDDLMemberName'
抛出一个无法找到控件的错误。
使用Control的uniqueID,mggvDDLMemberName是'ct100 $ MainContent $ UserGroupGridView $ GroupMemberGridView $ .. $ mggvDDLMemberName这会产生ControlToValidate在表单标记之外的错误,因为MainContent是PlaceContentHolder:
ControlToValidate = ((DropDownList)tFooterControls.FindControl("mggvDDLMemberName")).UniqueID;
尝试消除'ct100',使控件位于占位符内。我试试这个:
ControlToValidate = ((Dropdown) this.Form.FindControl("MainContent").FindControl("UserGroupGridView").FindControl("ct102").FindControl("GroupMemberGridView").FindControl("ctl13").FindControl("mggvDDLMemberName")).ID;
它会抛出无法找到控件的错误。 我真的不知道如何做到这一点或是否可以做到...... :( 我试过客户端解决方案无济于事。我可能需要再次调查一下。
更新 我回到了验证器的原始设计,而不是动态添加它们。这是带有验证器的FooterTemplate标记:
<FooterTemplate>
<asp:DropDownList ID="mggvDDLMemberName" runat="server" class="chosen-single" data-placeholder="Choose member…">
</asp:DropDownList>
<asp:RequiredFieldValidator ID="ReqValueDDLMemberInsert" runat="server" InitialValue="0" ControlToValidate="mggvDDLMemberName" ValidationGroup="InsertGroupMemberValidation" ErrorMessage="Selection required." CssClass="message-error-dropdown">
</asp:RequiredFieldValidator>
</FooterTemplate>
这是开始验证的添加按钮:
<FooterTemplate>
<asp:Button ID="mggvAddButton" runat="server" CommandName="Add" Text="Add Member" Width="90%" CssClass="gridActionbutton" CausesValidation="true" ValidationGroup="InsertGroupMemberValidation" >
</asp:Button>
</FooterTemplate>
答案 0 :(得分:2)
我正在添加一个新答案,以澄清一次&amp;对于所有案例中需要设置BaseValidator.ControlToValidate
的所有内容,包括后代/嵌套控件,因为有很多问题。我希望将来可能会对其他人以及当前的提问者使用。
我在上面找到的引用不正确/不足,其他地方的帖子也说明应该设置为Control.ID
或Control.UniqueID
。在所有案例中工作的代码使用.NET 4中添加的方法:Control.GetUniqueIDRelativeTo(Control control)
。我无法在网络上的任何地方找到任何使用示例(包括此处的stackoverflow)。给定BaseValidator validator
和Control control
,一旦将它们添加到页面的控件层次结构中,就需要以下内容:
validator.ControlToValidate = control.GetUniqueIDRelativeTo(validator);
GetUniqueIDRelativeTo
的文档不正确/误导。它声明它返回&#34;指定控件的UniqueID属性的前缀部分&#34 ;;实际上它返回&#34;后缀&#34;部分,即前缀 right 的部分,这是方法名称所暗示的。实际上,它会在从左侧删除control.UniqueID
后返回剩余validator.NamingContainer.UniqueID
的右侧部分。这会正确处理后代/嵌套控件。
将BaseValidator.ControlToValidate
设置为Control.ID
或Control.UniqueID
只是上述情况的退化情况,这些情况适用于特殊情况(并且GetUniqueIDRelativeTo()
无论如何都会返回相同的结果)。如果(且仅当)验证器和控件位于相同 NamingContainer 中,则Control.ID
有效;如果(且仅当)验证器的 NamingContainer 是页面,那么Control.UniqueID
有效。它们都不适用于其他嵌套/后代情况。
值得注意的是,如果控件的 NamingContainer 不与验证者 NamingContainer 相同或后代,则control.GetUniqueIDRelativeTo(validator)
转throw new InvalidOperationException("This control is not a descendent of the NamingContainer of '<validator>'")
。当ASP.NET生成有关无法找到要进行验证的控件的错误时,这就是您最终导致错误的原因。在这种情况下,您需要在页面工作之前对其进行排序,方法是将验证器移动到控件所在位置或最高位置。
对于原始提问者:ID
和UniqueID
对于她的原始代码都不正确,如上所述。我认为她最后通过将验证器从一个单独的位置/ NamingContainer移动到与DropDownList控件相同的位置/ NamingContainer来解决它,因此现在能够摆脱ID
退化的情况。
答案 1 :(得分:1)
这对我有用... 不需要唯一的ID,而是ValidationGroup名称。 所以,我在FooterTemplate的标记中创建了所有控件。但我没有命名ValidationGroup属性。我在代码隐藏中做到了这一点。 这是下拉列表,验证器和按钮的标记:
<FooterTemplate>
<asp:DropDownList runat="server"
ID="mggvDDLMemberName"
class="chosen-single"
data-placeholder="Choose member…">
</asp:DropDownList>
<asp:RequiredFieldValidator runat="server"
ID="ReqValueDDLMemberInsert"
InitialValue="0"
ControlToValidate="mggvDDLMemberName"
ErrorMessage="Selection required."
CssClass="message-error-dropdown">
</asp:RequiredFieldValidator>
</FooterTemplate>
<FooterTemplate>
<asp:Button runat="server"
ID="mggvAddButton"
CommandName="Add"
Text="Add Member"
Width="90%"
CssClass="gridActionbutton"/>
</FooterTemplate>
在RowDataBound事件中,当我将数据绑定到下拉列表时,我为每个控件命名ValidationGroup。
protected void UserGroupGridView_RowDataBound(object sender, GridViewRowEventArgs e)
{
try
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
int tiGroupID = Convert.ToInt32(UserGroupGridView.DataKeys[e.Row.RowIndex].Value.ToString());
GridView tgvGroupMember = (GridView)e.Row.FindControl("GroupMemberGridView");
populateGroupMemberGrid(tgvGroupMember, tiGroupID);
//Get the Footer controls
Control tFooterControls = CommonMethods.getFooterControls(tgvGroupMember);
DropDownList tddlRecipientNames = tFooterControls.FindControl("mggvDDLMemberName") as DropDownList;
m_strXmlTableData = m_pagingClient.GetAllPossibleGroupMembers(m_strUserID, tiGroupID);
DataTable tdtAllGroupMembers = CommonMethods.ParseXML(m_strXmlTableData);
tddlRecipientNames.DataSource = tdtAllGroupMembers;
tddlRecipientNames.DataTextField = tdtAllGroupMembers.Columns["MemberName"].ToString();
tddlRecipientNames.DataValueField = tdtAllGroupMembers.Columns["MemberID"].ToString();
tddlRecipientNames.ValidationGroup = "InsertMember" + tiGroupID.ToString();
tddlRecipientNames.DataBind();
tddlRecipientNames.Items.Insert(0, new ListItem("", "0"));//This is needed for the jquery-chosen dropdown to add data-holder text
RequiredFieldValidator validator = (RequiredFieldValidator)tFooterControls.FindControl("ReqValueDDLMemberInsert");
validator.ControlToValidate = ((DropDownList)tFooterControls.FindControl("mggvDDLMemberName")).GetUniqueIDRelativeTo(validator);
validator.ErrorMessage = "Selection required.";
validator.CssClass = "message-error-dropdown";
validator.ValidationGroup = "InsertMember" + tiGroupID.ToString();
Button tbtnAdd = tFooterControls.FindControl("mggvAddButton") as Button;
tbtnAdd.ValidationGroup = "InsertMember" + tiGroupID.ToString();
tbtnAdd.CausesValidation = true;
}
}
catch (Exception ex)
{
logger.ErrorException(ex.Message, ex);
Response.Redirect("~/Error.aspx?use=" + m_strUserType);
}
}
我希望这可以帮助别人并节省一点时间。
答案 2 :(得分:0)
我自己正在做这样的事情。根据我的理解(例如http://forums.asp.net/t/952691.aspx?Problem+in+Custom+Control+Unable+to+find+Control+To+Validate+Property+),验证者的ControlToValidate
必须 设置为控件的ID
提供它被放入同样的 NamingContainer 作为控件或可以设置为控件的UniqueID
提供验证器放在实际中页即可。
[编辑:此段和链接的说明不充分/不完整;请参阅下面的新单独帖子,以获得正确的讨论和解决方案。]
我认为网格/转发器中的每一行都是它自己的NamingContainer。无论如何,如果您尝试(坚持UniqueID
)将验证器添加到页面级别(请注意,validator.ID
必须本身是唯一的,或者不设置它? ),现在这会使你的情况有效吗?我有点想知道......
P.S。
或者,要对ID
使用控件的ControlToValidate
,您必须在控件旁边添加验证器,即将其添加到DropDownList的父的控件集合中,而不是在您所在的位置把它?