Использование ValidationGroup и клиентской проверки с ASP.NET Custom Server Control
Я создаю пользовательский серверный элемент управления для генерации элементов кнопок с определенной разметкой и обработчиками JavaScript для моего приложения Web Forms. Они, конечно, способны вызывать обратные передачи, поэтому я бы хотел, чтобы они работали с любым из элементов управления проверки ASP для проверки формы, особенно на стороне клиента.
Эта кнопка управления сервером поддерживает OnClientClick
свойство испускать onclick
атрибут в теге кнопки с предоставленным кодом (в основном используется для простого повторного подтверждения, когда пользователь нажимает кнопку удаления для представления списка или аналогичного), поэтому с помощью 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#)
Вот код для простого пользовательского элемента управления кнопки, который поддерживает 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);
}
}
Пожалуйста, ознакомьтесь с реализацией кнопок.NET Framework. Особенно метод 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, вам нужны эти две вещи в вашем 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;
}
options.ClientSubmit = false; это секрет