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

支持 AJAX 的可折叠表单部分

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.57/5 (4投票s)

2008年12月30日

CPOL

6分钟阅读

viewsIcon

41859

downloadIcon

215

一个 AJAX 控件,可以隐藏或显示表单的一部分,包括处理嵌套在该部分中的验证器。

引言

在许多情况下,我们可能需要实现复杂的表单,其中包含多个部分,这些部分可以根据用户的输入进行隐藏或显示。

在这些场景中遇到的问题是,我们想要隐藏或显示的部分可能包含必须禁用的验证器,以便表单能够回发。这可以通过服务器端代码轻松实现,但这会涉及一次往返服务器的行程,为了性能考虑,我们希望避免这种情况。

要使用 JavaScript 禁用验证器,我们必须保留所有验证器的引用,并且在隐藏表单的一部分时,必须禁用所有验证器,在显示它时,必须重新启用它们。

此控件旨在让所有这些工作对开发人员透明。开发人员唯一需要做的是将其添加到表单中,并将所有控件及其验证器嵌入其中。然后,它会处理所有必需的嵌套验证器的启用/禁用,以及显示/隐藏其中的所有控件。

例如,考虑以下表单

collapsed.PNG

当用户单击复选框时,我们也希望显示表单的第二部分

the_entire_form.PNG

已知新显示的三个字段是必填的,如果我们不在隐藏表单底部时禁用它们的验证器,它将不会回发,实际上,由于那些将包含在隐藏的 DIV 中,它甚至不会显示验证错误消息。

使用代码

从客户端角度看

此控件是一个 AJAX 控件,这意味着页面上的每个控件实例都将生成一个相应的 AJAX (JavaScript) 对象实例,该实例基于 'AjaxCollapsibleFormSection.js' 文件中定义的组件。

基本上,它是一个具有几个属性和必要算法来显示和隐藏表单部分的组件。之所以使用 AJAX 组件模型来实现它,是因为我们希望在文件中能够拥有一个以上的可折叠部分,因此,在 JavaScript 端,每个实例都应该有自己的验证器列表和其他属性。因此,最好的方法是拥有一个代表一个具有所有嵌入属性(这只是封装原则)的部分的 JavaScript 对象。

要使控件启用 AJAX,我们必须实现 IScriptControl 接口,该接口包含两个成员。一个用于获取 JavaScript 文件的引用,另一个用于 ScriptControlDescriptor 对象列表。

此控件的 ScriptControlDescriptor 非常简单,因为它包含以下属性

  • Validators:所有验证器 ID 的数组。
  • GroupName:一个任意字符串,用于在页面上将部分组合在一起,并使其外观互斥(显示一个部分时,具有相同组名的其他所有部分都将被隐藏)。
  • Exclusive/Inclusive
  • IsVisibleSection
  • ShowHideControl:这是一个 ElementProperty,这意味着它将转换为指向复选框的 JavaScript 对象引用,其状态将显示或隐藏该部分。
  • ShowControl:指向单选按钮的引用,选中该单选按钮时将显示该部分。
  • HideCoontrol:指向单选按钮的引用,选中该单选按钮时将隐藏该部分。

以下是实现 IScriptControl 接口的代码

IEnumerable<ScriptDescriptor> IScriptControl.GetScriptDescriptors()
{
    ValidateShowHideControls();
    ScriptControlDescriptor desc = 
      new ScriptControlDescriptor("SABBEL.Web.Controls" + 
      ".Ajax.CollapsibleFormSection", this.ClientID);
    string[] validatorsArray = new string[_validators.Count];
    _validators.CopyTo(validatorsArray, 0);
    desc.AddProperty("Validators", validatorsArray);
    desc.AddProperty("GroupName", GroupName);
    desc.AddProperty("Exclusive", Exclusive); 
    desc.AddProperty("Inclusive", Inclusive);
    desc.AddProperty("IsVisibleSection", IsVisibleSection);
    if (ShowHideControl!=null)
        desc.AddElementProperty("ShowHideControl", ShowHideControl.ClientID);
    if (HideControl != null)
        desc.AddElementProperty("HideControl", HideControl.ClientID);
    if (ShowControl != null)
        desc.AddElementProperty("ShowControl", ShowControl.ClientID);
    yield return desc;
}

IEnumerable<ScriptReference> IScriptControl.GetScriptReferences()
{
    ScriptReference reference = new ScriptReference(
      "SABBEL.Web.Controls.Ajax.AjaxCollapsibleFormSection.js", 
      "SABBEL.Web.Controls.Ajax"); 
    yield return reference;
}

在 JavaScript 端,“SABBEL.Web.Controls.Ajax.CollapsibleFormSection”类有几个方法。其中最重要的是 ShowHide,它将根据第一个参数的值来显示或隐藏该部分。此方法将依次调用“ResetValidators”来启用或禁用验证器,具体取决于我们是显示还是隐藏该部分。

另一个方法“InitializeCollapsibleForms”被注册为在 AJAX Toolkit 加载后立即启动。这是通过调用 add_load 方法实现的。

Sys.Application.add_load(InitializeCollapsibleForms);

也就是说,一旦整个页面加载完成,它将检查页面中的所有部分,并根据控制它们的控件(复选框或单选按钮)的状态初始显示或隐藏它们。

在 JavaScript 文件中,您还可以找到在选中或取消选中复选框或单选按钮时调用的函数。这些函数的名称可以通过将名称传递给节控件来更改。有三个函数可以重命名(这样您就可以重写它们并添加任何额外的显示/隐藏前/后事件或处理)

属性名

默认值

JS 函数的签名

ShowEventHandler

ShowForm

function showForm(collapsableSectionId)

HideEventHandler

HideForm

function hideForm(collapsableSectionId)

ShowHideEventHandler

ShowHideForm

function showHideForm(showHideControl, collapsableSectionId)

如果您决定重命名函数并重写它们,签名必须与上表中的相同。您可以从服务器控件附带的 JavaScript 文件中提供的默认实现开始。

从服务器端角度看

在服务器端,此控件会解析所有子控件以查找任何验证器。所有验证器客户端 ID 都将保留在一个数组中,并通过其“Validators”属性传递给 AJAX 对象引用。如果“Recursive”属性设置为 true,则控件将递归解析子控件。这可能会影响性能,因此,默认情况下,Recursive 属性设置为 false

此外,它还会向已与该部分关联的复选框或单选按钮添加 JavaScript 事件处理程序。

就是这样。如您所见,大部分工作都在客户端使用 AJAX 组件完成,如上所述。

如何使用此控件

在页面中,只需用 AjaxCollapsibleFormSection 控件将您想要按需隐藏和显示的表单部分括起来,并指定哪个控件将触发显示和/或隐藏事件;在下面的示例中,控件是 CheckBox (checkbox1)。

<asp:CheckBox runat="server" 
      Text="show this section" ID="checkbox1" /> 

<cc1:AjaxCollapsibleFormSection ID="AjaxCollapsibleFormSection1"
  ShowHideControlName="checkBox1"
  GroupName="Group1"
  Exclusive="true"
  ShowHideEventHandler="showHideFormExclusive"
  runat="server"> 


<asp:RequiredFieldValidator ID="rfvFirstName" 
  runat="server" 
  ErrorMessage="First Name is mandatory"
  ControlToValidate="firstName"/>

First Name: <asp:TextBox runat="server" ID="firstName">
</asp:TextBox><br />

<asp:RequiredFieldValidator ID="RequiredFieldValidator1" 
  ErrorMessage="Last Name is mandatory" 
  runat="server" ControlToValidate="lastName"/>
  Last Name: <asp:TextBox runat="server" ID="lastName">
</asp:TextBox><br />
<asp:RequiredFieldValidator ID="RequiredFieldValidator2" 
  runat="server" ErrorMessage="Street address is mandatory" 
  ControlToValidate="address" /> 
Street Address: <asp:TextBox runat="server" ID="address">
</asp:TextBox><br /> 

</cc1:AjaxCollapsibleFormSection> 

示例应用

在示例应用程序中,有关于独占部分和递归控件的用法示例,以防该部分中包含嵌套的用户控件。

结论

这个控件对我以及我们的团队来说非常有用,因为我们可以非常轻松地使我们的表单更具动态性,而无需在每次需要折叠或显示其某个部分(因为验证器)时都要发布页面。起初,我们开始用旧的方式编写 JavaScript,使用数组列表和内联 JavaScript 来跟踪验证器 ID 等。但是,这个解决方案更加优雅和可重用,当然,作为面向对象,也更容易维护。

这是使用 AJAX 启用的控件可以实现的良好示例。关于 AJAX 控件还有很多可以说的,但希望这个能成为一个很好的起点。

一个增强功能是让这个控件与复选框和单选按钮解耦,并允许任何其他 Web 控件触发它;例如,我们可以有一个链接来显示该部分,并在页面上有一个链接来隐藏它。或者它可以是一个按钮、一个图像……

© . All rights reserved.