[英]Using ValidationGroup and Client-Side Validation with ASP.NET Custom Server Control
我正在创建一个自定义服务器控件,以为我的Web窗体应用程序生成具有特定标记和JavaScript处理程序的按钮元素。 当然,它们能够引起回发,因此我希望它们与ASP的任何验证控件一起进行表单验证,尤其是客户端框架。
此按钮服务器控件支持OnClientClick
属性,以使用提供的代码在button标记中发出onclick
属性(主要用于在用户单击列表视图或类似内容的删除按钮时进行简单的确认提示),因此请使用asp:Button
控件将验证脚本作为onclick属性发出的方法将是无效的。 实际上,在标准asp:Button
上同时指定OnClientClick
和ValidationGroup
属性的结果非常糟糕。 这是一个令人痛苦的显而易见的例子,说明为什么它不能立即使用:
页面标记
<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
属性外,我无法找到更多有关如何最好地实现此目的的文档。 我以为我在重写的AddAttributesToRender
方法中对Page.ClientSCript.RegisterForEventValidation
调用将Page.ClientSCript.RegisterForEventValidation
客户端验证,但是这似乎不像我想象的那样起作用。 如有必要,jQuery可用于将其他处理绑定到按钮的click事件:
自定义服务器按钮控件
<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
当前,此代码无法与同一ValidationGroup
的asp:CompareValidator
一起使用,以确定在将两个密码重置字段都发回服务器之前是否相等,并且一旦请求到达服务器端也不会进行验证。
使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);
}
}
继续执行Bui Cuion,您需要的是CS中的这两件事:
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; 是秘密
请看看.NET Framework Button的实现。 特别是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;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.