65.9K
CodeProject 正在变化。 阅读更多。
Home

ClickOnce 按钮服务器控件

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.75/5 (51投票s)

2004 年 4 月 14 日

CPOL

3分钟阅读

viewsIcon

316245

downloadIcon

2860

本文展示了如何用 ASP.NET 按钮控件做那些人们说不应该或不能做的事情。

引言

在经典 ASP 时代,当我们想阻止最终用户重复点击提交按钮时,我们会使用 JavaScript 禁用该按钮。 但在 ASP.NET 中,这不再那么简单了。 当您在客户端禁用任何表单元素时,实际上也会在服务器端禁用它,因为它的名称值对不会随表单 post 一起发送。 这样做的缺点是 button_click 事件现在变得毫无用处。 它永远不会被触发!

我已经在 ASP.NET 论坛上搜索过解决这个问题的优雅方案,并且看到了一些不错的解决方法,但没有一个能在点击后真正实现禁用按钮的效果。 所以我想出了我自己的办法。 请看 ClickOnceButton 服务器控件。

该服务器控件的行为与固有的按钮控件完全一样,除了两个新属性:DisableAfterClickDisabledText

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 的默认常量值为 __onceClickBtnIsHiddenFieldRegistered 函数只是确保该字段只注册一次。 这使我们有可能在表单上拥有多个在单击后禁用的按钮。

您可能想知道为什么我没有直接继承自 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 版本进行了测试。

© . All rights reserved.