I had the exact same problem. Use a CustomValidator instead of the CompareValidator. (The CustomValidator has a helpful attribute called ValidateEmptyText, which the CompareValidator lacks, at least in ASP.NET 2.0.)
You will need to program an appropriate ServerValidate function, as well as the ClientValidationFunction. The function signature for the javascript function is basically the same as for the ServerValidate function: source (object), args (ServerValidateEventArgs).
The trickiest part is that you will need to write custom code to access the "CompareTo" textbox, since that's not part of the CustomValidator. My fields were within a FormView; you may need to adjust the code to fit your particular circumstances. In the code below, "fv" is the name of that FormView.
Client-side validation:
<script type="text/javascript">
<!--
function cvPasswordRpt_Validate(source, args)
{
args.IsValid = (args.Value ==
document.getElementsByName("fv$tbPassword").item(0).value);
}
//-->
</script>
ASPX Code:
<label>New Password:</label>
<asp:TextBox ID="tbPassword" runat="server" CssClass="stdTextField"
TextMode="Password" ValidationGroup="edit" />
<br />
<label>Repeat New Password:</label>
<asp:TextBox ID="tbPasswordRpt" runat="server" CssClass="stdTextField"
TextMode="Password" ValidationGroup="edit" />
<asp:CustomValidator ID="cvPasswordRpt" runat="server" Display="Dynamic"
EnableClientScript="true" ValidationGroup="edit"
ControlToValidate="tbPasswordRpt" ValidateEmptyText="true"
ErrorMessage="Your passwords do not match."
ClientValidationFunction="cvPasswordRpt_Validate"
OnServerValidate="cvPasswordRpt_ServerValidate" />
Server-side validation (VB.NET):
Protected Sub cvPasswordRpt_ServerValidate(ByVal sender As Object,
ByVal e As ServerValidateEventArgs)
Dim _newPassword As String = DirectCast(fv.FindControl("tbPassword"),
TextBox).Text
e.IsValid = e.Value.Equals(_newPassword)
End Sub