I am creating a custom server control to generate button elements with specific markup and JavaScript handlers for my Web Forms application. They are, of course, able to cause postbacks, so I would like them to function with any of ASP's validation controls for form validation, especially the client-side framework.
This button server control supports an OnClientClick property to emit an onclick attribute in the button tag with the code provided (primarily used for a simple confirmation reprompt when a user clicks a delete button for a list view or similar), so using the asp:Button control's method of emitting the validation script as an onclick attribute will be pretty ineffectual. As a matter of fact, specifying both OnClientClick and ValidationGroup attributes on a standard asp:Button turns out pretty badly. Here's a painfully obvious example of why that's not working out of the box:
Page Markup
<asp:Button ID="btnSaveAsp" ValidationGroup="vgMyValidationGroup" OnClientClick="return true;" runat="server" />
Rendered Markup
<input type="submit" name="ctl00$cphBodyContent$lvMyList$ctrl0$btnSaveAsp" value="Save"  id="cphBodyContent_lvUsers_btnSaveAsp_0"
    onclick='return true; WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions("ctl00$cphBodyContent$lvMyList$ctrl0$btnSaveAsp", "", true, "vgMyValidationGroup", "", false, false))'>
Here is the existing non-working code for wiring up the control with validation. I was unable to find much documentation on how best to accomplish this with a method aside from emitting a similar onclick attribute. I thought my call to Page.ClientSCript.RegisterForEventValidation in the overridden AddAttributesToRender method would wire up the client-side validation, but that does not appear to be functioning as I assumed. If necessary, jQuery is available for use in binding additional handling to the button's click event:
Custom Server Button Control
<ToolboxData("<{0}:Button runat=server></{0}:Button>")> _
<ParseChildren(False)> _
<PersistChildren(True)> _
Public Class Button
    Inherits System.Web.UI.WebControls.WebControl
    Implements IPostBackDataHandler
    Public Sub New()
        MyBase.New(HtmlTextWriterTag.Button)
    End Sub
    <Category("Behavior")> _
    <DefaultValue("")> _
    Public Overridable Property PostBackUrl As String
        Get
            Return If(ViewState("PostBackUrl"), String.Empty)
        End Get
        Set(value As String)
            ViewState("PostBackUrl") = value
        End Set
    End Property
    <Category("Validation")> _
    <DefaultValue(True)> _
    Public Overridable Property CausesValidation As Boolean
        Get
            Return If(ViewState("CausesValidation"), True)
        End Get
        Set(value As Boolean)
            ViewState("CausesValidation") = value
        End Set
    End Property
    <Category("Validation")> _
    <DefaultValue("")> _
    Public Overridable Property ValidationGroup As String
        Get
            Return If(ViewState("ValidationGroup"), String.Empty)
        End Get
        Set(value As String)
            ViewState("ValidationGroup") = value
        End Set
    End Property
    <Category("Behavior")> _
    <DefaultValue("")> _
    <Description("Client-side script to be run when the button is clicked.")> _
    Public Property OnClientClick As String
        Get
            Return If(ViewState("OnClientClick"), String.Empty)
        End Get
        Set(value As String)
            ViewState("OnClientClick") = value
        End Set
    End Property
    Protected Overrides Sub AddAttributesToRender(writer As HtmlTextWriter)
        MyBase.AddAttributesToRender(writer)
        If Not String.IsNullOrEmpty(OnClientClick) Then
            writer.AddAttribute(HtmlTextWriterAttribute.Onclick, OnClientClick)
        End If
        Dim postBackOptions = GetPostBackOptions()
        If postBackOptions.TargetControl Is Me Then
            writer.AddAttribute(HtmlTextWriterAttribute.Name, ClientID)
        End If
        If Page IsNot Nothing Then
            Page.ClientScript.RegisterForEventValidation(postBackOptions)
        End If
    End Sub
    Protected Overridable Function GetPostBackOptions() As PostBackOptions
        Dim options As New PostBackOptions(Me) With {
            .ClientSubmit = False
        }
        If Page IsNot Nothing Then
            If CausesValidation AndAlso (Page.GetValidators(ValidationGroup).Count > 0) Then
                options.PerformValidation = True
                options.ValidationGroup = ValidationGroup
            End If
            If Not String.IsNullOrEmpty(PostBackUrl) Then
                options.ActionUrl = HttpUtility.UrlPathEncode(ResolveClientUrl(PostBackUrl))
            End If
        End If
        Return options
    End Function
End Class
Presently, this code does not function with an asp:CompareValidator in the same ValidationGroup to determine if two password reset fields are equal before posting back to the server, nor does validation occur once the request gets to the server side.