C# 带两个模板的模板化用户控件如何在其他模板中查找需要控件id的属性的控件

C# 带两个模板的模板化用户控件如何在其他模板中查找需要控件id的属性的控件,c#,.net,asp.net,user-controls,C#,.net,Asp.net,User Controls,我有一个带有两个模板的模板化用户控件,除了为其他模板中存在的控件设置id,如AssociatedControlID或ControlToValidate 我知道它们存在于两个不同的命名容器中,这会阻止它们相互查找,因此在下面的代码中,设置AssociatedControlID不能仅使用控件id。是否有一些技巧可以声明性地设置此项,或者我必须使用FindControl并在后面的代码中进行设置 这是我的控件布局: <uc1:Field ID="paramName" runat="server"&

我有一个带有两个模板的模板化用户控件,除了为其他模板中存在的控件设置id,如AssociatedControlID或ControlToValidate

我知道它们存在于两个不同的命名容器中,这会阻止它们相互查找,因此在下面的代码中,设置AssociatedControlID不能仅使用控件id。是否有一些技巧可以声明性地设置此项,或者我必须使用FindControl并在后面的代码中进行设置

这是我的控件布局:

<uc1:Field ID="paramName" runat="server">
    <LabelTemplate >
        <asp:Label ID="lblName" AssociatedControlID="txtValue" runat="server" >Label Text:</asp:Label>
    </LabelTemplate>
    <InputTemplate>
        <asp:TextBox ID="txtValue" runat="server" MaxLength="30"></asp:TextBox>
    </InputTemplate>
</uc1:Field>

标签文本:
编辑1:我甚至无法让它在代码隐藏中工作。我尝试将AssociatedControlID设置为.ID、.ClientID、.UniqueID,但我总是忘记需要哪个,所以我都尝试了。我还尝试从FindControl中查找控件。我可以从控件的父级找到它,但不能从父级的父级找到它。这很奇怪

编辑2:我想出了一个局部解决方案。它不适用于AssociatedControlID,但它确实适用于ControlToValidate,这实际上对我来说更重要。解决方法如下:在容器类中,必须重写FindControl,并使其指向两个级别。然后您将需要执行自己的FindControl,因为我尝试了Parent.Parent.FindControl,但它仍然没有找到控件,我不完全理解原因,因此我有一个扩展方法来枚举控件集合中的所有控件。我也不知道为什么它不能与标签的AssociatedControlID一起工作。也许在内部它调用FindControl的方式不同

我仍然觉得我错过了一些简单的事情

/// <summary>
/// This is a hack to get the validators in the label template to see the controls in the input template
/// just don't name any controls in the two templates the same thing
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
public override Control FindControl(string id)
{
    if (Parent == null && Parent.Parent == null)
    {
        return base.FindControl(id);
    }

    return Parent.Parent.Controls.All().Where(x => x.ID == id).FirstOrDefault();
}
//
///这是一种让标签模板中的验证器看到输入模板中的控件的方法
///只是不要将两个模板中的任何控件命名为相同的名称
/// 
/// 
/// 
公共覆盖控件FindControl(字符串id)
{
if(Parent==null&&Parent.Parent==null)
{
返回base.FindControl(id);
}
返回Parent.Parent.Controls.All(),其中(x=>x.ID==ID.FirstOrDefault();
}
以下是All扩展方法:

public static IEnumerable<Control> All(this ControlCollection controls)
{
    foreach (Control control in controls)
    {
        foreach (Control grandChild in control.Controls.All())
            yield return grandChild;

        yield return control;
    }
}
public static IEnumerable All(此控件集合控件)
{
foreach(控件中的控件)
{
foreach(Control.Controls.All()中的Control孙辈)
收益回报孙子;
收益率控制;
}
}
谢谢你帮我解决这个烦人的问题


Chris

对于ControlToValidate,可以在InputTemplate控件的类定义上使用ValidationPropertyAttribute。只需将代码更新为:

//"Text" is the name of the Property which returns the value to validate
[ValidationProperty("Text")] 
public class InputTemplate
{
    ...
    public string Text { set { txtValue.Text = value; } get { return txtValue.Text } }
}
现在,在代码隐藏中,您可以将RequiredFieldValidator的ControlToValidate属性设置为用户控件的ID: 例如,
RequiredFieldValidator 1.ControlToValidate=InputTemplate1.ID

至于标签的关联控件ID,我还没有弄清楚

祝你好运

肖恩