Verwenden von ValidationGroup und clientseitiger Validierung mit ASP.NET Custom Server Control
-
12-11-2019 - |
Frage
Ich erstelle ein benutzerdefiniertes Serversteuerelement, um Schaltflächenelemente mit bestimmten Markups und JavaScript-Handlern für meine Web Forms-Anwendung zu generieren.Sie sind natürlich in der Lage, Postbacks zu verursachen, daher möchte ich, dass sie mit allen ASP-Validierungskontrollen für die Formularvalidierung funktionieren, insbesondere mit dem clientseitigen Framework.
Dieses Button-Server-Steuerelement unterstützt eine OnClientClick
Eigenschaft zum Ausgeben eines onclick
Attribut im Schaltflächen-Tag mit dem bereitgestellten Code (wird hauptsächlich für eine einfache erneute Bestätigungsaufforderung verwendet, wenn ein Benutzer auf eine Schaltfläche zum Löschen für eine Listenansicht oder ähnliches klickt), also unter Verwendung von asp:Button
Die Methode des Controls, das Validierungsskript als Onclick-Attribut auszugeben, wird ziemlich wirkungslos sein.Tatsächlich wird beides angegeben OnClientClick
Und ValidationGroup
Attribute auf einem Standard asp:Button
fällt ziemlich schlecht aus.Hier ist ein schmerzlich offensichtliches Beispiel dafür, warum das nicht sofort funktioniert:
Seitenmarkierung
<asp:Button ID="btnSaveAsp" ValidationGroup="vgMyValidationGroup" OnClientClick="return true;" runat="server" />
Gerendertes Markup
<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))'>
Hier ist der vorhandene, nicht funktionierende Code zum Verdrahten der Steuerung mit Validierung.Ich konnte nicht viel Dokumentation darüber finden, wie man dies mit einer anderen Methode als der Ausgabe einer ähnlichen Methode am besten bewerkstelligen kann onclick
Attribut.Ich dachte, mein Anruf Page.ClientSCript.RegisterForEventValidation
im überschriebenen AddAttributesToRender
-Methode würde die clientseitige Validierung verkabeln, aber das scheint nicht so zu funktionieren, wie ich angenommen habe.Bei Bedarf steht jQuery zur Verfügung, um zusätzliche Verarbeitung an das Klickereignis der Schaltfläche zu binden:
Benutzerdefinierte Server-Schaltflächensteuerung
<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
Derzeit funktioniert dieser Code nicht mit einem asp:CompareValidator
im gleichen ValidationGroup
um zu ermitteln, ob zwei Passwort-Reset-Felder gleich sind, bevor sie an den Server zurückgesendet werden, und es findet auch keine Validierung statt, sobald die Anforderung auf der Serverseite eintrifft.
Lösung
Herstellung OnClientClick
Arbeiten Sie mit der clientseitigen Formularvalidierung
Seit der <asp:Button>
control verkettet den Wert von OnClientClick
Mit dem Formularvalidierungsskript können Sie sie am einfachsten zusammenarbeiten lassen return false
wenn Sie die Formularübermittlung blockieren möchten und nichts unternehmen möchten, wenn Sie möchten, dass die Schaltfläche das Formular validiert und übermittelt:
OnClientClick="if (!confirm('Are you sure?')) return false;"
Wenn Sie jedoch unbedingt schreiben möchten return confirm('Are you sure?')
, dann können Sie den Formularvalidierungscode in einen Ereignis-Listener verschieben (wie Sie vorschlagen) oder ihn umschließen OnClientClick
Code wie folgt:
writer.AddAttribute(
HtmlTextWriterAttribute.Onclick,
"if (!(function() { " + this.OnClientClick + "; return true; })()) return false;" +
this.Page.ClientScript.GetPostBackEventReference(options, false));
Serverseitige Formularvalidierung
Sie müssen das implementieren IPostBackEventHandler
Schnittstelle und rufen Sie die auf Page.Validate
Methode.Der ClientScriptManager.RegisterForEventValidation
Die Methode wird zur Ereignisvalidierung (Verhinderung unbefugter oder böswilliger Postbacks) und nicht zur Formularvalidierung verwendet.
Beispielcode (C#)
Hier ist der Code für ein einfaches benutzerdefiniertes Schaltflächensteuerelement, das Folgendes unterstützt OnClientClick
Und 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);
}
}
Andere Tipps
Bitte werfen Sie einen Blick auf die Button-Implementierung im .NET Framework.Insbesondere die AddAttributesToRender-Methode.Anschließend können Sie den Code so ändern, dass er wie gewünscht funktioniert:
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;
}
Fortsetzung von Bui Cuion, was Sie brauchen, sind diese 2 Dinge in Ihrem 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);
Und
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;ist das Geheimnis