Использование ValidationGroup и проверки на стороне клиента с ASP.NET пользовательский серверный контроль
Я создаю пользовательский серверный элемент управления для создания элементов кнопок с определенной разметкой и обработчиками JavaScript для моего приложения Web Forms. Они, конечно, способны вызывать обратные отклики, поэтому я хотел бы, чтобы они работали с любым из элементов управления проверки ASP для проверки формы, особенно на стороне клиента.
Этот серверный элемент управления button поддерживает свойство OnClientClick
для выделения атрибута onclick
в теге button с предоставленным кодом (в основном используется для простого reprompt подтверждения, когда пользователь нажимает кнопку delete для представления списка или подобного), поэтому использование метода asp:Button
элемента управления для создания сценария проверки в качестве атрибута onclick будет довольно неэффективным. На самом деле, указание как OnClientClick
, так и ValidationGroup
атрибутов на стандартном asp:Button
получается довольно плохо. Вот болезненно очевидный пример того, почему это не работает из коробки:
Разметка Страницы
<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
. Я думал, что мой вызов Page.ClientSCript.RegisterForEventValidation
в переопределенном методе AddAttributesToRender
приведет к проверке на стороне клиента, но это, похоже, не работает, как я предполагал. При необходимости jQuery можно использовать для привязки дополнительной обработки к кнопке. нажмите событие:
Управление Пользовательской Кнопкой Сервера
<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
В настоящее время этот код не работает с asp:CompareValidator
в том же ValidationGroup
, чтобы определить, равны ли два поля сброса пароля перед отправкой обратно на сервер, и проверка не происходит, как только запрос попадает на серверную сторону.
3 ответа:
Создание
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#)
Вот код для пользовательского элемента управления bare-bones, который поддерживает
OnClientClick
иValidationGroup
:[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); } }
Пожалуйста, обратите внимание на .Чистый рамках реализации кнопки. Особенно метод 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; }
Продолжая Bui Cuion то, что вам нужно, это эти 2 вещи в вашем cs 1:
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; }
Варианты.ClientSubmit = false; is the secret