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

创建和维护 ASP.NET Web Forms 的最佳方法 - MForm Web Controls 入门

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.85/5 (14投票s)

2009年7月19日

Ms-PL

10分钟阅读

viewsIcon

164135

downloadIcon

481

本文向读者介绍了 MForm Web Controls,这是一组控件,提供了一种非常高效且灵活的创建 ASP.NET Web Forms 的方法。

源代码

本文介绍的项目托管在 mform.codeplex.com。您可以在此处找到最新版本(该项目最近已更新)。但是,如果链接失效,您也可以随时下载本地副本 - 3.42 MB

目录

引言

您很可能看过“可能世界上最好的啤酒”的广告。您可能不太可能听说过MForm Web Controls。如果您和我一样,是一名在编写收集和处理大量数据的 Web Forms 时感到挣扎的 Web 开发人员,那么您一定会觉得本文介绍的控件很有趣。

项目背景

MForm Web Controls 项目始于我工作的波兰 Bank Millennium 的 IT 部门,最近已根据 Microsoft 公共许可证发布。如果您曾经申请过贷款或抵押贷款,您就知道银行希望尽可能多地了解其客户,以最大程度地降低将过多资金借给未来无力偿还的个人所带来的风险。所有这些数据都由银行顾问在与客户会面期间输入到银行的内联网应用程序中。

银行 IT 开发人员的职责是:

  • 定义业务部门想要收集的信息的数据契约(数据结构和数据限制);
  • 创建 Web Forms(一个或多个)以根据数据契约收集数据;
  • 根据数据限制验证 Web Forms 中的字段;
  • 将字段中的数据合并到数据结构中。

最后,数据被发送到别处,用于决定客户的贷款事宜。

让我印象深刻的是,所有这些任务似乎都可以至少部分地自动化。表单可以直接从数据契约生成(在我们的例子中,数据契约使用 XML schema 定义),验证(至少是基本验证,如检查字段是否必填、最大长度、是否匹配模式或最大值)也可以从数据契约获取,最后,数据合并(创建 XML 输出而不是字段集合)也可以自动完成。

然而,解决方案必须足够可扩展,以便:

  • 允许在生成后通过视觉方式修改创建的表单;
  • 允许添加自定义业务验证,这些验证可以与数据验证一样工作;
  • 使表单创建过程尽可能简单,以便即使是经验不足的开发人员也可以准备至少一个 Web Forms 草图;
  • 高效并使用 AJAX 来消除不必要的 postback;
  • 尽可能使用通用的 ASP.NET 控件和解决方案;

生成您的第一个 MForm Web Forms

您还可以观看介绍后续步骤的视频,此处

1. 获取契约

为了能够生成表单,您首先需要数据定义。最好将这些定义存储在 XML schema 中(XML schema 提供了一种声明式定义数据限制的方法,而代码目前不支持),但如果您不熟悉 XML schema,也可以从托管库生成表单。

在下面的示例中,我们将使用一个Customer 数据定义

Customer 包含:

  • 名字和姓氏,长度不能超过 20 个字符;
  • 身份证号;
  • 出生日期(日期类型);
  • 性别,只能是 'Male' 或 'Female';
  • 以及地址,包括:
    • 街道,最大长度 100;
    • 门牌号,最大长度 10;
    • 公寓号,可选;
    • 邮政编码,必须匹配“两位数字 - 三位数字”的模式;
    • 城市,最大长度 50。

假设您已经下载了项目代码,您会在BM.Tools.WebControls.MForm.Example/Schemas/Customer.xsd 文件中找到 Customer 数据定义。

2. 使用 MForm Root 控件创建页面

  1. 在 Visual Studio 2008 中打开项目。
  2. 在 **BM.Tools.WebControls.MForm.Example** 项目中,选择“新建项”->“Web 内容窗体”。
  3. 选择 Site.Master 作为母版页。
  4. 将打开一个页面,看起来会是这样:
  5. <%@ Page 
        Title="" 
        Language="C#" 
        MasterPageFile"~/Site.Master" 
        AutoEventWireup="true" 
        CodeBehind="WebForm1.aspx.cs" 
        Inherits="BM.Tools.WebControls.MForm.Example.WebForm1" 
    %>
        <asp:content runat="server" 
           contentplaceholderid="ContentPlaceHolder1" id="Content1">
    </asp:content>
  6. 切换到设计模式。
  7. 在工具箱中找到 Root 控件。
  8. Root 控件拖放到页面上。应该会是这样:
  9. 将 **Designer mode**(设计器模式)更改为 **Edit**(编辑)

3. 点击“从 schema 加载根模板”按钮

您将看到生成器表单:

4. 选择契约源和位置

点击 **Choose**(选择)按钮,然后选择 XML schema、WSDL 或程序集文件。然后点击 **Open**(打开)。**Element name**(元素名称)下拉列表将填充可用的元素(一个 XML schema 文件可能包含多个元素定义,同样,一个程序集也可能包含多个类)。

5. 选择元素

一旦从下拉列表中选择了一个元素,就会显示元素树。您可以决定哪些定义将被渲染到表单中。默认情况下,整个树都准备好进行渲染。要更改此设置,请取消选中元素旁边的复选框。

6. 点击“生成

点击 **Generate**(生成)后,Root 控件将被填充内容。Root 设计器模式将更改为 **View**(查看)模式,这样您就可以看到结果(设计器模式下的渲染并不完美,实际页面显示可能会有所不同)。

generation_7.png

7. 切换到源代码视图

生成的表单在源代码视图中可用,并且可以自由修改。我们将仔细查看生成的代码。

<%@ Page Title="" Language="C#" 
    MasterPageFile="~/Site.Master" AutoEventWireup="true"
    CodeBehind="WebForm1.aspx.cs" 
    Inherits="BM.Tools.WebControls.MForm.Example.WebForm1" %>

<%@ Register Assembly="BM.Tools.WebControls.MForm" 
    Namespace="BM.Tools.WebControls.MForm.Controls"
    TagPrefix="mf" %>
<%@ Register Assembly="BM.Tools.WebControls.MForm" 
    Namespace="BM.Tools.WebControls.MForm.Controls.Additions"
    TagPrefix="mfadd" %>
<%@ Register Assembly="BM.Tools.WebControls.MForm" 
    Namespace="BM.Tools.WebControls.MForm.Controls.ValueHandlers"
    TagPrefix="mfvh" %>
<asp:Content ID="Content1" 
           ContentPlaceHolderID="ContentPlaceHolder1" 
           runat="server">
    <mf:Root ID="Root1" runat="server" Name="Root1">
        <UriMappings>
            <mf:UriMapping Namespace="http://www.w3.org/2001/XMLSchema" Prefix="xs" />
            <mf:UriMapping Namespace="" Prefix="" />
        </UriMappings>
        <Contents>
            <mf:Branch runat="server" Name="Customer">
                <Contents>
                    <mf:Leaf runat="server" Name="FirstName" Ordinal="1">
                        <Additions>
                            <mfadd:Restriction runat="server" 
                               RestrictionType="MaxLength" Value="20" />
                        </Additions>
                    </mf:Leaf>
                    <mf:Leaf runat="server" Name="Surname" Ordinal="2">
                        <Additions>
                            <mfadd:Restriction runat="server" 
                              RestrictionType="MaxLength" Value="20" />
                        </Additions>
                    </mf:Leaf>
                    <mf:Leaf runat="server" Name="Sex" Ordinal="3">
                        <ValueHandler>
                            <mfvh:ListBoxValueHandler runat="server" Value="">
                                <ListBox Rows="1">
                                    <asp:ListItem Value="Female">Female</asp:ListItem>
                                    <asp:ListItem Value="Male">Male</asp:ListItem>
                                </ListBox>
                            </mfvh:ListBoxValueHandler>
                        </ValueHandler>
                    </mf:Leaf>
                    <mf:Leaf runat="server" Name="NationalId" Ordinal="4">
                    </mf:Leaf>
                    <mf:Leaf runat="server" DataType="Date" 
                       Name="BirthDate" Ordinal="5">
                    </mf:Leaf>
                    <mf:Branch runat="server" Name="Address" Ordinal="6">
                        <Contents>
                            <mf:Leaf runat="server" Name="Street" Ordinal="1">
                                <Additions>
                                    <mfadd:Restriction runat="server" 
                                       RestrictionType="MaxLength" Value="100" />
                                </Additions>
                            </mf:Leaf>
                            <mf:Leaf runat="server" Name="HouseNumber" Ordinal="2">
                                <Additions>
                                    <mfadd:Restriction runat="server" 
                                      RestrictionType="MaxLength" Value="10" />
                                </Additions>
                            </mf:Leaf>
                            <mf:Leaf runat="server" MinOccurs="0" 
                                       Name="FlatNumber" Ordinal="3">
                                <Additions>
                                    <mfadd:Restriction runat="server" 
                                       RestrictionType="MaxLength" Value="10" />
                                </Additions>
                            </mf:Leaf>
                            <mf:Leaf runat="server" Name="PostCode" Ordinal="4">
                                <Additions>
                                    <mfadd:Restriction runat="server" 
                                        RestrictionType="Pattern" Value="\d{2}-\d{3}" />
                                </Additions>
                            </mf:Leaf>
                            <mf:Leaf runat="server" Name="Post" Ordinal="5">
                                <Additions>
                                    <mfadd:Restriction runat="server" 
                                       RestrictionType="MaxLength" Value="50" />
                                </Additions>
                            </mf:Leaf>
                            <mf:Leaf runat="server" Name="City" Ordinal="6">
                                <Additions>
                                    <mfadd:Restriction runat="server" 
                                      RestrictionType="MaxLength" Value="50" />
                                </Additions>
                            </mf:Leaf>
                        </Contents>
                    </mf:Branch>
                </Contents>
            </mf:Branch>
        </Contents>
        <Validator Placement="BeforeContent"></Validator>
    </mf:Root>
</asp:Content>

ASPX 中生成的代码乍一看可能有些吓人。生成了很多数据。当然,除非您想以某种方式更改它,否则您不需要理解所有生成的代码。

Root 控件内部有三个元素:

  • UriMappings
  • 目录
  • 验证器

UriMappings

UriMappings 元素保存有关数据定义中的前缀和命名空间映射的信息。在我们的示例中,没有使用命名空间,因此只有一个映射,即空前缀映射到空命名空间。

验证器

Validator 元素负责显示表单验证错误。它将 MForm 树插入到 ASP.NET 页面的验证机制中。

Contents 属性

最后,Contents 元素是 Root 控件中最重要的一部分。Contents 属性是一个在页面渲染时实例化的模板,因此它可以包含任何有效的 ASPX 脚本代码:HTML 代码、Web 控件等。默认情况下,它只包含生成的控件。您可以看到一个 Branch 控件,其属性为 Customer。此控件也有一个 Contents 属性,其中可能包含任何 ASPX 脚本代码。

分支和叶子

Branch 控件代表具有子项的数据定义。收集文本的数据定义由 Leaf 控件表示。Leaf 控件不包含 Contents 属性。相反,它们可能包含 ValueHandler 元素,该元素提供了 MForm 树与应该实际收集数据的控件之间的通信。

值处理器

默认情况下,所有数据都使用 TextBox 收集,因此默认值处理器是 TextBoxValueHandler。MForm 框架为通用的 .NET 窗体 Web 控件提供了值处理器。如果您想将自己的自定义控件与 MForm 框架一起使用,则必须为该控件实现值处理器。

Leaf 控件 Sex 中包含一个不同的值处理器的示例。数据定义只允许在该元素中使用两个值:Male 或 Female。这已在表单中转换为 ListBox 控件,其中包含两个相应的列表项。如果您更喜欢使用 RadioButtonList 而不是 ListBox,可以将值处理器更改为 RadioButtonListValuehandler,并将其内部控件设置为 RadioButtonList

数据类型

您还记得我们的客户数据定义有一个 BirthDate 字段,其类型为 date 吗?您现在可以看到 BirthDate 叶子有一个 DataType 属性,其值为 Date。这断言该字段的数据必须以有效的日期格式提供。

新增功能

Leaf 控件中还可能找到另一个定义是 AdditionsAdditions 可能包含继承自 Addition 控件的控件列表。Addition 控件为 MForm 控件添加了一些逻辑;例如,它可以添加数据约束。在生成后直接找到的 Addition 控件是从 XML schema 获取的数据限制。因此,如果在我们的数据契约中,PostCode 字段必须匹配模式:2 位数字 - 3 位数字,那么在名为 PostCode 的叶子节点中,我们将有一个 Restriction 添加项,其限制类型为 Pattern,值为 **\d{2}-\d{3}**。

Ordinal 属性

最后一件值得解释的事情是 Ordinal 属性。

MForm Web Controls 的设计旨在最大限度地简化 Web Forms 的创建,同时仍提供生成后编辑这些表单的可能性。我们可以自由修改生成的表单,但要记住,生成的 MForm 子项*不能被移出其父项*。

因此,在 Contents 属性内部,允许:

  • 添加一些 HTML 代码或控件;
  • 将 MForm 子控件放置在这些添加的控件内部(例如,所有 Leaf 控件都可以放置在 table 中);
  • 提取一部分生成的代码并将其放置在外部用户控件中,并在 Contents 中添加对该控件的引用;
  • 更改 MForm 同级元素的顺序。

在从 MForm 控件树创建输出 XML 时,会考虑两个因素:

  1. XML 节点的层次结构 - 如果 MForm 子项未移出其父项,则 MForm 层次结构保持不变,因此 XML 节点的层次结构也将有效。
  2. XML 节点的顺序 - 由于控件的顺序可以改变,因此会生成 Ordinal 属性。在渲染输出 XML 时,MForm 控件将按 Ordinal 属性值排序,这断言了 XML 节点的顺序是有效的。

如果您不关心 XML 节点的顺序(例如,使用 .NET XmlSerializer 类将 XML 反序列化到对象通常会完全忽略 XML 节点的顺序),则可以在生成器“Options”(选项)选项卡下关闭 Ordinal 属性的生成。

8. 运行页面

向页面添加一个 ASP Button。然后将其设置为启动页并运行项目。您将看到表单可以正常工作并经过验证。您还可以看到数据在 postback 过程中得以保留。

默认情况下,每个限制都有一个显示的默认错误文本。如果您想自定义显示的错误文本(在上面的示例中,告知正则表达式不匹配对大多数用户来说可能不太方便),只需设置限制的 ErrorText 属性即可。

如果您在表单填写完毕后获取 Root 控件的 OutputXml 属性,您将获得一个符合我们用于生成表单的 XML schema 的 XML 文档。这比单独处理每个字段要方便得多。获取 OutputXml 属性不需要表单经过验证。因此,如果您在没有验证的情况下点击一个按钮,上面表单的输出 XML 将是:

<?xml version="1.0" encoding="utf-16"?>
<Customer>
  <FirstName>Andrew</FirstName>
  <Surname>Broomstick</Surname>
  <NationalId>APD400003</NationalId>
  <BirthDate>1979-03-01</BirthDate>
  <Address>
    <Street>Universal</Street>
    <HouseNumber>34</HouseNumber>
    <PostCode>00-33</PostCode>
    <Post>Warsaw</Post>
    <City>Warsaw</City>
  </Address>
</Customer>

下一步?

我将尝试发布更多关于 MForm Web Controls 的文章。该项目仍处于 alpha 阶段,但我们非常接近首次稳定发布。在此之前,欢迎您通过 BM.Tools.WebControls.MForm.Example 项目熟悉 MForm Web Controls。我们非常感谢您在 mform.codeplex.com 提交 bug 和评论。您也可以在 mform.org 查看示例项目。

历史记录

  • 2009-07-19 - 本文的初始版本。
  • 2009-07-20 - 添加了指向视频的链接,该视频遵循本文所述的步骤。
  • 2009-07-21 - 添加了源代码的本地副本,添加了页面内容。
  • 2009-07-24 - 添加了运行页面以及输出 XML 的屏幕截图。
© . All rights reserved.