Использование ValidationGroup и проверки на стороне клиента с помощью ASP.NET Пользовательского серверного управления
-
12-11-2019 - |
Вопрос
Я создаю пользовательский серверный элемент управления для генерации элементов кнопок с определенной разметкой и обработчиками 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
чтобы определить, совпадают ли два поля для сброса пароля, перед отправкой обратно на сервер, проверка также не выполняется, как только запрос поступает на серверную сторону.
Решение
Изготовление 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;
}
продолжая покупку, все, что вам нужно, - это эти 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 = ложь;в этом секрет