ClickOnce 按钮服务器控件






4.75/5 (51投票s)
本文展示了如何用 ASP.NET 按钮控件做那些人们说不应该或不能做的事情。
引言
在经典 ASP 时代,当我们想阻止最终用户重复点击提交按钮时,我们会使用 JavaScript 禁用该按钮。 但在 ASP.NET 中,这不再那么简单了。 当您在客户端禁用任何表单元素时,实际上也会在服务器端禁用它,因为它的名称值对不会随表单 post 一起发送。 这样做的缺点是 button_click
事件现在变得毫无用处。 它永远不会被触发!
我已经在 ASP.NET 论坛上搜索过解决这个问题的优雅方案,并且看到了一些不错的解决方法,但没有一个能在点击后真正实现禁用按钮的效果。 所以我想出了我自己的办法。 请看 ClickOnceButton
服务器控件。
该服务器控件的行为与固有的按钮控件完全一样,除了两个新属性:DisableAfterClick
和 DisabledText
。
当 DisableAfterClick
为 true 时,按钮将在客户端点击后被禁用。 如果设置了 DisabledText
,则按钮的文本将在按钮禁用后设置为 DisabledText
。 如果您想要获得一些视觉提示(例如将按钮的文本更改为“正在处理..”),这将非常有用。
主要工作发生在 AddAttributesToRender
事件中。
Protected Overrides Sub AddAttributesToRender(ByVal writer As HtmlTextWriter)
Dim strOnClick As String
If IsNothing(MyBase.Page) Then
MyBase.Page.VerifyRenderingInServerForm(Me)
End If
writer.AddAttribute(HtmlTextWriterAttribute.Type, "submit")
writer.AddAttribute(HtmlTextWriterAttribute.Name, MyBase.UniqueID)
writer.AddAttribute(HtmlTextWriterAttribute.Value, Me.Text)
If Not IsNothing(MyBase.Page) And Me.CausesValidation_
And MyBase.Page.Validators.Count > 0 Then
If Me.DisableAfterClick Then
strOnClick = Me.GetClickOnceClientValidateEvent()
Else
strOnClick = Me.GetClientValidateEvent()
End If
If MyBase.Attributes.Count > 0 And Not _
IsNothing(MyBase.Attributes("onclick")) Then
strOnClick = String.Concat(MyBase.Attributes("onclick"), strOnClick)
MyBase.Attributes.Remove("onclick")
End If
writer.AddAttribute("language", "javascript")
writer.AddAttribute(HtmlTextWriterAttribute.Onclick, strOnClick)
ElseIf DisableAfterClick = True Then
strOnClick = Me.GetOnceClickJavascript()
If MyBase.Attributes.Count > 0 And Not _
IsNothing(MyBase.Attributes("onclick")) Then
strOnClick = String.Concat(MyBase.Attributes("onclick"), strOnClick)
MyBase.Attributes.Remove("onclick")
End If
writer.AddAttribute("language", "javascript")
writer.AddAttribute(HtmlTextWriterAttribute.Onclick, strOnClick)
End If
MyBase.AddAttributesToRender(writer)
End Sub
这以编程方式创建按钮,并确定按钮是否导致验证以及页面上是否存在验证器,或者按钮是否只需要被禁用。 您会注意到它调用了三个截然不同的属性。 这些是让魔法发生的原因。 它们如下:
Friend ReadOnly Property GetClientValidateEvent() As String
Get
Return "if (typeof(Page_ClientValidate) _
== 'function') Page_ClientValidate(); "
End Get
End Property
Friend ReadOnly Property GetClickOnceClientValidateEvent() As String
Get
Return "if (typeof(Page_ClientValidate) == 'function') _
{ if(Page_ClientValidate()) { " + _
GetOnceClickJavascript + " }} else { " + _
GetOnceClickJavascript + " }"
End Get
End Property
Friend ReadOnly Property GetOnceClickJavascript() As String
Get
Return "document.getElementsByName('" + _
Me.OnceClickBtnName + "').item(0).setAttribute('name'," + _
"this.getAttribute('name')); this.disabled = true; " + _
IIf(DisabledText = String.Empty, String.Empty, _
"this.value = '" + DisabledText + "';") + _
"this.form.submit();"
End Get
End Property
属性 GetClientValidateEvent()
返回与框架通常附加的相同的 JavaScript,如果您的按钮控件导致验证并且页面上存在验证器。 这是为了处理您在页面上放置了按钮,设置为在单击后不禁用,并且您有验证器的情况。
属性 GetClickOnceClientValidateEvent()
返回上述脚本的稍微修改的版本。 这处理了页面上有验证器并且您希望在单击后禁用按钮的情况。 但是您想确保只有在 Page_ClientValidate()
返回 true 时才禁用它,或者在非 IE 浏览器的情况下,它只会禁用该按钮并提交。
属性 GetOnceClickJavascript()
返回禁用按钮的基本 JavaScript 集。 它还确保按钮在 post 中被发送,以便触发按钮单击。 它通过将隐藏字段的 name 属性与按钮的 name 交换来实现这一点。 框架只需要看到发送过来的控件的 name/ID 即可触发其 click 事件。 隐藏字段在控件的 OnInit(EventArgs)
事件中注册。
Protected Overrides Sub OnInit(ByVal e As EventArgs)
If Me.DisableAfterClick And Not Me.IsHiddenFieldRegistered Then
MyBase.Page.RegisterHiddenField(Me.OnceClickBtnName, "")
End If
MyBase.OnInit(e)
End Sub
Private Function IsHiddenFieldRegistered() As Boolean
For Each ctl As Control In MyBase.Page.Controls
If TypeOf ctl Is HtmlControls.HtmlInputHidden Then
If ctl.ID = Me.OnceClickBtnName Then
Return True
End If
End If
Next
Return False
End Function
OnceClickBtnValue
的默认常量值为 __onceClickBtn
。 IsHiddenFieldRegistered
函数只是确保该字段只注册一次。 这使我们有可能在表单上拥有多个在单击后禁用的按钮。
您可能想知道为什么我没有直接继承自 System.Web.UI.WebControls.Button
类。 好吧,原因是 AddAttributesToRender
事件。 我本来可以只劫持该事件并添加我在这里拥有的相同代码,而不必经历创建属性、函数等的整个过程。 问题是我仍然需要调用 MyBase.AddAttributesToRender
,这将最终调用 System.Web.UI.WebControls.WebControl
类中的 AddAttributesToRender
。 如果我继承自 Button
类,我最终会得到两个 onclick
,并且无法控制验证事件中输出的 JavaScript。 这让我拥有完全的控制权。
要在您自己的项目中使用它,只需将 *clickoncebutton* 程序集添加到您的工具箱中,然后将其拖放到您的 webform 上即可! 享受!
注意:在 IE 6.0 和 NS 7.0 上使用 .NET framework 的 1.1 版本进行了测试。