The .NET validation framework has two parts, the client Javascript validation and the server validation. That means that the Javascript code needs a value to validate and the server validation needs a property to validate.

So, first step, you create your web user control by putting some controls in it. Then, you want to add a validator to the page to reference the newly created user control. And you get the error "Control '{0}' referenced by the ControlToValidate property of '{1}' cannot be validated.". Why? because every control to be validated needs to be decorated with the ValidationProperty attribute:
[ValidationProperty("Text")]
public partial class ucDate : System.Web.UI.UserControl

Adding the first line to the control tells the validation framework to use the Text property of the UserControl.

Next step, you run the page and you notice the javascript doesn't work. The client validation works on html controls, by looking (recursively) for a 'value' attribute. When one looks at the source code, though, there is no html control that has the id of the user control. It doesn't use a span or a div to encapsulate its controls. All the controls have the id to show they are children to the user control, but the actual user control does not appear in the html source. So what is there to do?

<div id='<%=ClientID %>'></div>

You put all the controls in the ascx file of the User Control into this div. There you go! The validation works!

There is one more quirk regarding web user controls that have more children that render an html object with a 'value' attribute. In that case, remember that the validation starts from the very top, in our case the div. One could build simple javascript functions on the onchange or onsubmit javascript events, for example, to add a value attribute to the div. Best way would be using the onsubmit event, but be careful that the validation sequence also runs on the onsubmit event.

TextBox2.Attributes["onchange"]="document.getElementById('"+ClientID+"').value=this.value";


On popular demand, here is a complete example codeThis is a control that holds two TextBox controls. The control will be validated both on server and client by the value of the second Textbox, the first will be ignored.


using System;
using System.Web.UI;

[ValidationProperty("SecondTextboxValue")]
public partial class vuc : UserControl
{
public string SecondTextboxValue
{
get { return tbValidated.Text; }
}

protected void Page_Load(object sender, EventArgs e)
{
string script =
string.Format(
@"var vuc=document.getElementById('{0}');
var tb=document.getElementById('{1}');
if (vuc&&tb) {{
tb.vuc=vuc;
tb.onchange=function() {{ this.vuc.value=this.value; }}
}}"
,
ClientID, tbValidated.ClientID);

ScriptManager.RegisterStartupScript(Page, Page.GetType(), UniqueID + "_submit", script, true);
}
}


The ascx looks like this:
<%@ Control Language="C#" AutoEventWireup="true" CodeFile="vuc.ascx.cs" Inherits="vuc" %>
<div id="<%=ClientID %>"> value="<%=tbValidated.Text%>"
<asp:TextBox ID="tbIgnored" runat="server"></asp:TextBox>
<asp:TextBox ID="tbValidated" runat="server"></asp:TextBox>
</div>


How it works:
  • The javascript validator will look for an html element with the same id as the user control. If it has a value attribute, it will be validated, else it will go to the next control in the hierarchy. If the containing div would not have a value attribute, then the validation would have occured on the first textbox value, as the first element that has a value attribute. That's why the value attribute will be set on textbox change and when first loading the page.
  • The server validation will work because of the user control property that exposes the Text value of the second textbox and the ValidationProperty attribute that decorates the code.


Comments

Sagar

Code on the below link worked without any hassle. Simply Amazing http://www.dotnetmafia.com/blogs/coryrobinson/archive/2007/04/24/validating-custom-composite-web-controls.aspx

Sagar

Anonymous

Could you post some sample code for the web user control and main page ? This sounds like what I want to do but cannot get it working from just the description

Anonymous

Post a comment