2

我正在創建一個自定義服務器控件,爲我的Web窗體應用程序生成具有特定標記和JavaScript處理程序的按鈕元素。當然,它們能夠引起回發,因此我希望它們能夠與任何ASP的驗證控件一起用於表單驗證,尤其是客戶端框架。通過ASP.NET自定義服務器控件使用ValidationGroup和客戶端驗證

此按鈕服務器控件支持OnClientClick屬性在按鈕標記中發出onclick屬性並提供了代碼(主要用於在用戶單擊列表視圖或類似對象的刪除按鈕時進行的簡單確認重新提示),因此使用asp:Button控件將驗證腳本作爲onclick屬性發布的方法將非常不起作用。事實上,在標準asp:Button上同時指定OnClientClickValidationGroup屬性的結果非常糟糕。下面是爲什麼不工作開箱的痛苦明顯的例子:

頁面標記

<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會連接客戶端驗證,但似乎沒有按照我的假設運行。如果必要的話,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 

目前,該代碼不會在同一ValidationGroupasp:CompareValidator發揮作用確定兩個密碼重置字段在發回服務器之前是否相同,一旦請求到達服務器端,驗證也不會發生。

+0

你能提供一個例子,說明OnClientClick將被真實地設置爲什麼(而不僅僅是'return true')嗎? – 2012-03-03 04:50:02

+0

'return confirm(「你確定要刪除這個項目?」)或其他任何重新提示。實際上我已經想到了解決方法,我很快就會發布我的解決方案。它涉及了一點點挖掘ASP.NET的回發處理的內涵,但如果我只是將驗證作爲監聽器添加到click事件上,那麼事情就很好。 – lsuarez 2012-03-03 22:08:41

回答

6

製作與客戶端表單驗證OnClientClick工作

由於控制串接的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#)

下面是支持OnClientClickValidationGroup一個最基本的自定義按鈕控件的代碼:

[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); 
    } 
} 
+0

感謝您提供答案。無論用戶響應如何,我都希望進行驗證客戶端,這就是爲什麼我不太喜歡串聯。你的回答給了我一個引起服務器端驗證的好看,所以我明白這一點。在將按鈕從實施「IPostBackDataHandler」移動後,我忘了將驗證移入我的'RaisePostBackEvent'處理程序。 – lsuarez 2012-03-05 14:28:54

0

請看看.NET框架的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; 
} 
+0

我已經演示了一個場景,其中默認的ASP.NET按鈕處理在上面的帖子中是不充分的。此實現已無法解決使用OnClientClick和驗證組的問題。 – lsuarez 2012-02-27 15:30:35

0

繼續裴Cuion你需要的是這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; 
    } 

options.ClientSubmit = false;是祕密

相關問題