Templated User Control with two templates how to find control in other template for properties which require control id
I have a templated user control with two templates, and everything works, except for setting id's for thing like AssociatedControlID or ControlToValidate for controls which exists in the other template.
I understand that they exists in two different naming containers which prevents them from finding each other, so in the code below setting the AssociatedControlID does't work with just the control id. Is there some trick for setting this declaratively, or am I going to have to use FindControl and set it in the code behind?
Here is my control layout:
<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>
EDIT 1: I can't even get it to work setting it in the code behind. I tried setting the AssociatedControlID to .ID, .ClientID, .UniqueID I always forget which is required, so I tried them all. I also tried finding the Control from FindControl. I am able to find it from the parent of the control, but not the parent's parent. That is very strange.
EDIT 2: I have come up with a partial solution. It does not开发者_开发问答 work for the AssociatedControlID, but it does work for ControlToValidate which is more important to me actually. Here is the work-around: In your Container Class you must override FindControl, and make it point up two levels. You will then need to do your own FindControl, as i tried Parent.Parent.FindControl and it still did not find the controls, I don't completely understand why, so I have an extension method to enumerate all controls in a control collection. I also don't know why it does not work with AssociatedControlID for labels. Maybe internally it calls FindControl differently.
I still feel like I am missing something simple.
/// <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();
}
Here is the All Extension Method:
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;
}
}
Thanks for any help with this annoying problem.
Chris
For ControlToValidate, you can use the ValidationPropertyAttribute on the class definition of the InputTemplate control. Simply update your code-behind as:
//"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 } }
}
Now in your code-behind, you can set your RequiredFieldValidator's ControlToValidate Property to the ID of the User Control:
eg. RequiredFieldValidator1.ControlToValidate = InputTemplate1.ID;
As for the AssociatedControlID for the Label, I haven't figured this out yet.
Best of Luck,
Shawn
精彩评论