El uso de ValidationGroup y la Validación del Cliente con ASP.NET Control de Servidor Personalizado
-
12-11-2019 - |
Pregunta
Estoy creando un servidor personalizado de control para generar botón de elementos específicos de marcado y los controladores JavaScript para mi aplicación de Formularios Web forms.Ellos son, por supuesto, capaz de provocar las devoluciones, así que me gustaría que vuelvan a funcionar con cualquiera de ASP controles de validación para la validación de formularios, especialmente en el marco de cliente.
Este botón de control de servidor soporta un OnClientClick
la propiedad de emitir un onclick
atributo en el botón de la etiqueta con el código provisto (utilizado principalmente por una simple confirmación reprompt cuando un usuario hace clic en un botón de borrar para una vista de lista o similares), por lo que el uso de la asp:Button
control del método de emisión de la validación de secuencia de comandos como un atributo onclick va a ser bastante ineficaz.Como cuestión de hecho, la especificación OnClientClick
y ValidationGroup
los atributos de un estándar asp:Button
resulta bastante mal.He aquí una dolorosamente obvio ejemplo de por qué lo que no funciona fuera de la caja:
Marcado De Página
<asp:Button ID="btnSaveAsp" ValidationGroup="vgMyValidationGroup" OnClientClick="return true;" runat="server" />
Marcado Representado
<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))'>
Aquí es el existente no-código de trabajo para el cableado hasta el control y la validación.No he podido encontrar mucha documentación sobre la mejor manera de lograr esto con un método aparte de la emisión de una similar onclick
atributo.Pensé que mi llamada a Page.ClientSCript.RegisterForEventValidation
en el reemplazado AddAttributesToRender
método de alambre hasta la validación en el cliente, pero que no parece estar funcionando como supuse.Si es necesario, jQuery está disponible para su uso en la unión de manipulación adicional para el evento click del botón:
Servidor Personalizado Botón De 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
En la actualidad, este código no funciona con un asp:CompareValidator
en el mismo ValidationGroup
para determinar si dos de restablecimiento de contraseña campos son iguales antes de la publicación de vuelta al servidor, ni validación de ocurrir una vez que la solicitud se presenta en el lado del servidor.
Solución
Hacer OnClientClick
trabajo con el lado del cliente para la validación de formularios
Desde el <asp:Button>
control de concatena el valor de OnClientClick
con el formulario de validación de secuencia de comandos, la forma más fácil de hacer que funcionen juntos es return false
cuando se desea bloquear el envío del formulario, y no hacer nada si desea que el botón para validar y enviar el formulario:
OnClientClick="if (!confirm('Are you sure?')) return false;"
Sin embargo, si usted no desea escribir return confirm('Are you sure?')
, a continuación, puede mover el formulario de validación de código para un detector de eventos (como lo sugieren), o usted puede ajustar el OnClientClick
un código como este:
writer.AddAttribute(
HtmlTextWriterAttribute.Onclick,
"if (!(function() { " + this.OnClientClick + "; return true; })()) return false;" +
this.Page.ClientScript.GetPostBackEventReference(options, false));
Validación del lado del servidor
Usted necesita para implementar el IPostBackEventHandler
interfaz y llamar a la Page.Validate
método.El ClientScriptManager.RegisterForEventValidation
el método utilizado para la validación de un evento (prevención no autorizados o maliciosos de devoluciones), no para la validación del formulario.
El código de ejemplo (C#)
Aquí está el código para un escueto botón personalizado de control que soporta OnClientClick
y 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);
}
}
Otros consejos
Por favor, eche un vistazo a la implementación del botón Framework .NET.Especialmente método addattributeestorender.Luego puede modificar el código para que funcione la forma en que desea:
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;
}
Continuando Bui CUIRON Lo que necesitas son estas 2 cosas en tu 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);
y
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;es el secreto