繁体   English   中英

在ASP.NET自定义服务器控件中使用ValidationGroup和客户端验证

[英]Using ValidationGroup and Client-Side Validation with ASP.NET Custom Server Control

我正在创建一个自定义服务器控件,以为我的Web窗体应用程序生成具有特定标记和JavaScript处理程序的按钮元素。 当然,它们能够引起回发,因此我希望它们与ASP的任何验证控件一起进行表单验证,尤其是客户端框架。

此按钮服务器控件支持OnClientClick属性,以使用提供的代码在button标记中发出onclick属性(主要用于在用户单击列表视图或类似内容的删除按钮时进行简单的确认提示),因此请使用asp:Button控件将验证脚本作为onclick属性发出的方法将是无效的。 实际上,在标准asp:Button上同时指定OnClientClickValidationGroup属性的结果非常糟糕。 这是一个令人痛苦的显而易见的例子,说明为什么它不能立即使用:

页面标记

<asp:Button ID="btnSaveAsp" ValidationGroup="vgMyValidationGroup" OnClientClick="return true;" runat="server" />

渲染标记

<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))'>

这是用于验证连接的现有非工作代码。 除了发出类似的onclick属性外,我无法找到更多有关如何最好地实现此目的的文档。 我以为我在重写的AddAttributesToRender方法中对Page.ClientSCript.RegisterForEventValidation调用将Page.ClientSCript.RegisterForEventValidation客户端验证,但是这似乎不像我想象的那样起作用。 如有必要,jQuery可用于将其他处理绑定到按钮的click事件:

自定义服务器按钮控件

<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

当前,此代码无法与同一ValidationGroupasp:CompareValidator一起使用,以确定在将两个密码重置字段都发回服务器之前是否相等,并且一旦请求到达服务器端也不会进行验证。

使OnClientClick与客户端表单验证一起使用

由于<asp:Button>控件将OnClientClick的值与表单验证脚本连接在一起,因此使它们一起工作的最简单方法是,当您要阻止提交表单时, return false ;如果希望按钮进行验证,则不执行任何操作并提交表格:

OnClientClick="if (!confirm('Are you sure?')) return false;"

但是,如果您绝对要编写return confirm('Are you sure?') ,则可以将表单验证代码移动到事件侦听器(如您建议的那样),或者可以像这样包装OnClientClick代码:

writer.AddAttribute(
    HtmlTextWriterAttribute.Onclick,
    "if (!(function() { " + this.OnClientClick + "; return true; })()) return false;" +
    this.Page.ClientScript.GetPostBackEventReference(options, false));

服务器端表单验证

您需要实现IPostBackEventHandler接口并调用Page.Validate方法。 ClientScriptManager.RegisterForEventValidation方法用于事件验证(防止未经授权或恶意的回发),而不用于表单验证。

样例代码(C#)

这是支持OnClientClickValidationGroup自定义按钮控件的代码:

[ParseChildren(false)]
[PersistChildren(true)]
public class Button : WebControl, IPostBackEventHandler
{
    private static readonly object EventClick = new object();

    public Button()
        : base(HtmlTextWriterTag.Button)
    {
    }

    public bool CausesValidation
    {
        get { return ((bool?)this.ViewState["CausesValidation"]) ?? true; }
        set { this.ViewState["CausesValidation"] = value; }
    }

    public string ValidationGroup
    {
        get { return (string)this.ViewState["ValidationGroup"] ?? ""; }
        set { this.ViewState["ValidationGroup"] = value; }
    }

    public string OnClientClick
    {
        get { return (string)this.ViewState["OnClientClick"] ?? ""; }
        set { this.ViewState["OnClientClick"] = value; }
    }

    public event EventHandler Click
    {
        add { this.Events.AddHandler(EventClick, value); }
        remove { this.Events.RemoveHandler(EventClick, value); }
    }

    protected override void AddAttributesToRender(HtmlTextWriter writer)
    {
        base.AddAttributesToRender(writer);
        writer.AddAttribute(HtmlTextWriterAttribute.Name, this.UniqueID);

        if (this.Page != null && this.Enabled)
        {
            PostBackOptions options = this.GetPostBackOptions();
            writer.AddAttribute(
                HtmlTextWriterAttribute.Onclick,
                this.OnClientClick + this.Page.ClientScript.GetPostBackEventReference(options, false));
        }
    }

    protected virtual PostBackOptions GetPostBackOptions()
    {
        PostBackOptions options = new PostBackOptions(this) { ClientSubmit = false };

        if (this.Page != null)
        {
            if (this.CausesValidation && this.Page.GetValidators(this.ValidationGroup).Count > 0)
            {
                options.PerformValidation = true;
                options.ValidationGroup = this.ValidationGroup;
            }
        }

        return options;
    }

    protected virtual void OnClick(EventArgs e)
    {
        EventHandler handler = (EventHandler)this.Events[EventClick];

        if (handler != null)
        {
            handler(this, e);
        }
    }

    void IPostBackEventHandler.RaisePostBackEvent(string eventArgument)
    {
        if (this.CausesValidation)
        {
            this.Page.Validate(this.ValidationGroup);
        }

        this.OnClick(EventArgs.Empty);
    }
}

继续执行Bui Cuion,您需要的是CS中的这两件事:

   protected override void AddAttributesToRender(HtmlTextWriter writer)
    {
        bool useSubmitBehavior = this.UseSubmitBehavior;
        if (this.Page != null)
        {
            this.Page.VerifyRenderingInServerForm(this);
        }
        if (useSubmitBehavior)
        {
            writer.AddAttribute(HtmlTextWriterAttribute.Type, "submit");
        }
        else
        {
            writer.AddAttribute(HtmlTextWriterAttribute.Type, "button");
        }
        PostBackOptions postBackOptions = this.GetPostBackOptions();
        writer.AddAttribute(HtmlTextWriterAttribute.Value, this.Text);
        bool isEnabled = base.IsEnabled;
        string firstScript = string.Empty;
        if (isEnabled)
        {
            firstScript = this.EnsureEndWithSemiColon(this.OnClientClick);
            if (base.HasAttributes)
            {
                string strOnClick = base.Attributes["onclick"];
                if (strOnClick != null)
                {
                    firstScript = firstScript + this.EnsureEndWithSemiColon(strOnClick);
                    base.Attributes.Remove("onclick");
                }
            }
            if (!this.AutoPostBack)
            {
                firstScript = this.MergeScript(this.OnClientClick, "return false;");
            }
            if (this.Page != null)
            {
                string postBackEventReference = this.Page.ClientScript.GetPostBackEventReference(postBackOptions, false);
                if (postBackEventReference != null)
                {
                    firstScript = this.MergeScript(firstScript, postBackEventReference);
                }
            }
        }
        if (this.Page != null)
        {
            this.Page.ClientScript.RegisterForEventValidation(postBackOptions);
        }
        if (firstScript.Length > 0)
        {
            writer.AddAttribute(HtmlTextWriterAttribute.Onclick, firstScript);
        }
        if (this.Enabled && !isEnabled)
        {
            writer.AddAttribute(HtmlTextWriterAttribute.Disabled, "disabled");
        }
        base.AddAttributesToRender(writer);

 protected virtual PostBackOptions GetPostBackOptions()
    {
        PostBackOptions options = new PostBackOptions(this, string.Empty);
        options.ClientSubmit = false;
        if (this.Page != null)
        {
            if (this.CausesValidation && (this.Page.GetValidators(this.ValidationGroup).Count > 0))
            {
                options.PerformValidation = true;
                options.ValidationGroup = this.ValidationGroup;
            }
            if (!string.IsNullOrEmpty(this.PostBackUrl))
            {
                options.ActionUrl = HttpUtility.UrlPathEncode(base.ResolveClientUrl(this.PostBackUrl));
            }
        }
        return options;
    }

options.ClientSubmit = false; 是秘密

请看看.NET Framework Button的实现。 特别是AddAttributesToRender方法。 然后,您可以修改代码以使其按您希望的方式工作:

public class Button : WebControl, IButtonControl, IPostBackEventHandler
{
    private readonly static object EventClick;

    private readonly static object EventCommand;

    [WebSysDescription("Button_CausesValidation")]
    [WebCategory("Behavior")]
    [DefaultValue(true)]
    [Themeable(false)]
    public bool CausesValidation
    {
        get
        {
            object item = this.ViewState["CausesValidation"];
            if (item == null)
            {
                return true;
            }
            else
            {
                return (bool)item;
            }
        }
        set
        {
            this.ViewState["CausesValidation"] = value;
        }
    }

    [Bindable(true)]
    [DefaultValue("")]
    [Themeable(false)]
    [WebCategory("Behavior")]
    [WebSysDescription("WebControl_CommandArgument")]
    public string CommandArgument
    {
        get
        {
            string item = (string)this.ViewState["CommandArgument"];
            if (item == null)
            {
                return string.Empty;
            }
            else
            {
                return item;
            }
        }
        set
        {
            this.ViewState["CommandArgument"] = value;
        }
    }

    [Themeable(false)]
    [WebCategory("Behavior")]
    [WebSysDescription("WebControl_CommandName")]
    [DefaultValue("")]
    public string CommandName
    {
        get
        {
            string item = (string)this.ViewState["CommandName"];
            if (item == null)
            {
                return string.Empty;
            }
            else
            {
                return item;
            }
        }
        set
        {
            this.ViewState["CommandName"] = value;
        }
    }

    [Themeable(false)]
    [WebSysDescription("Button_OnClientClick")]
    [DefaultValue("")]
    [WebCategory("Behavior")]
    public string OnClientClick
    {
        get
        {
            string item = (string)this.ViewState["OnClientClick"];
            if (item != null)
            {
                return item;
            }
            else
            {
                return string.Empty;
            }
        }
        set
        {
            this.ViewState["OnClientClick"] = value;
        }
    }

    [DefaultValue("")]
    [WebCategory("Behavior")]
    [WebSysDescription("Button_PostBackUrl")]
    [Editor("System.Web.UI.Design.UrlEditor, System.Design, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", typeof(UITypeEditor))]
    [Themeable(false)]
    [UrlProperty("*.aspx")]
    public string PostBackUrl
    {
        get
        {
            string item = (string)this.ViewState["PostBackUrl"];
            if (item == null)
            {
                return string.Empty;
            }
            else
            {
                return item;
            }
        }
        set
        {
            this.ViewState["PostBackUrl"] = value;
        }
    }

    [WebSysDescription("Button_Text")]
    [WebCategory("Appearance")]
    [DefaultValue("")]
    [Localizable(true)]
    [Bindable(true)]
    public string Text
    {
        get
        {
            string item = (string)this.ViewState["Text"];
            if (item == null)
            {
                return string.Empty;
            }
            else
            {
                return item;
            }
        }
        set
        {
            this.ViewState["Text"] = value;
        }
    }

    [WebSysDescription("Button_UseSubmitBehavior")]
    [WebCategory("Behavior")]
    [DefaultValue(true)]
    [Themeable(false)]
    public bool UseSubmitBehavior
    {
        get
        {
            object item = this.ViewState["UseSubmitBehavior"];
            if (item == null)
            {
                return true;
            }
            else
            {
                return (bool)item;
            }
        }
        set
        {
            this.ViewState["UseSubmitBehavior"] = value;
        }
    }

    [WebSysDescription("PostBackControl_ValidationGroup")]
    [WebCategory("Behavior")]
    [DefaultValue("")]
    [Themeable(false)]
    public string ValidationGroup
    {
        get
        {
            string item = (string)this.ViewState["ValidationGroup"];
            if (item == null)
            {
                return string.Empty;
            }
            else
            {
                return item;
            }
        }
        set
        {
            this.ViewState["ValidationGroup"] = value;
        }
    }

    static Button()
    {
        Button.EventClick = new object();
        Button.EventCommand = new object();
    }

    public Button() : base(47)
    {
    }

    protected override void AddAttributesToRender(HtmlTextWriter writer)
    {
        bool useSubmitBehavior = this.UseSubmitBehavior;
        if (this.Page != null)
        {
            this.Page.VerifyRenderingInServerForm(this);
        }
        if (!useSubmitBehavior)
        {
            writer.AddAttribute(HtmlTextWriterAttribute.Type, "button");
        }
        else
        {
            writer.AddAttribute(HtmlTextWriterAttribute.Type, "submit");
        }
        PostBackOptions postBackOptions = this.GetPostBackOptions();
        string uniqueID = this.UniqueID;
        if (uniqueID != null && (postBackOptions == null || postBackOptions.TargetControl == this))
        {
            writer.AddAttribute(HtmlTextWriterAttribute.Name, uniqueID);
        }
        writer.AddAttribute(HtmlTextWriterAttribute.Value, this.Text);
        bool isEnabled = base.IsEnabled;
        string empty = string.Empty;
        if (isEnabled)
        {
            empty = Util.EnsureEndWithSemiColon(this.OnClientClick);
            if (base.HasAttributes)
            {
                string item = base.Attributes["onclick"];
                if (item != null)
                {
                    empty = string.Concat(empty, Util.EnsureEndWithSemiColon(item));
                    base.Attributes.Remove("onclick");
                }
            }
            if (this.Page != null)
            {
                string postBackEventReference = this.Page.ClientScript.GetPostBackEventReference(postBackOptions, false);
                if (postBackEventReference != null)
                {
                    empty = Util.MergeScript(empty, postBackEventReference);
                }
            }
        }
        if (this.Page != null)
        {
            this.Page.ClientScript.RegisterForEventValidation(postBackOptions);
        }
        if (empty.Length > 0)
        {
            writer.AddAttribute(HtmlTextWriterAttribute.Onclick, empty);
            if (base.EnableLegacyRendering)
            {
                writer.AddAttribute("language", "javascript", false);
            }
        }
        if (this.Enabled && !isEnabled)
        {
            writer.AddAttribute(HtmlTextWriterAttribute.Disabled, "disabled");
        }
        base.AddAttributesToRender(writer);
    }

    protected virtual PostBackOptions GetPostBackOptions()
    {
        PostBackOptions postBackOption = new PostBackOptions(this, string.Empty);
        postBackOption.ClientSubmit = false;
        if (this.Page != null)
        {
            if (this.CausesValidation && this.Page.GetValidators(this.ValidationGroup).Count > 0)
            {
                postBackOption.PerformValidation = true;
                postBackOption.ValidationGroup = this.ValidationGroup;
            }
            if (!string.IsNullOrEmpty(this.PostBackUrl))
            {
                postBackOption.ActionUrl = HttpUtility.UrlPathEncode(this.ResolveClientUrl(this.PostBackUrl));
            }
            postBackOption.ClientSubmit = !this.UseSubmitBehavior;
        }
        return postBackOption;
    }

    protected virtual void OnClick(EventArgs e)
    {
        EventHandler item = (EventHandler)base.Events[Button.EventClick];
        if (item != null)
        {
            item(this, e);
        }
    }

    protected virtual void OnCommand(CommandEventArgs e)
    {
        CommandEventHandler item = (CommandEventHandler)base.Events[Button.EventCommand];
        if (item != null)
        {
            item(this, e);
        }
        base.RaiseBubbleEvent(this, e);
    }

    protected internal override void OnPreRender(EventArgs e)
    {
        base.OnPreRender(e);
        if (this.Page != null && base.IsEnabled)
        {
            if ((!this.CausesValidation || this.Page.GetValidators(this.ValidationGroup).Count <= 0) && string.IsNullOrEmpty(this.PostBackUrl))
            {
                if (!this.UseSubmitBehavior)
                {
                    this.Page.RegisterPostBackScript();
                }
            }
            else
            {
                this.Page.RegisterWebFormsScript();
                return;
            }
        }
    }

    protected virtual void RaisePostBackEvent(string eventArgument)
    {
        base.ValidateEvent(this.UniqueID, eventArgument);
        if (this.CausesValidation)
        {
            this.Page.Validate(this.ValidationGroup);
        }
        this.OnClick(EventArgs.Empty);
        this.OnCommand(new CommandEventArgs(this.CommandName, this.CommandArgument));
    }

    protected internal override void RenderContents(HtmlTextWriter writer)
    {
    }

    private void System.Web.UI.IPostBackEventHandler.RaisePostBackEvent(string eventArgument)
    {
        this.RaisePostBackEvent(eventArgument);
    }

    [WebCategory("Action")]
    [WebSysDescription("Button_OnClick")]
    public event EventHandler Click;
    [WebCategory("Action")]
    [WebSysDescription("Button_OnCommand")]
    public event CommandEventHandler Command;
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM