本文档是Visual C# 教程 (转至 Visual Basic 教程 ) 。
本教程中,我们将构建一个用户界面,上面有一个具备分页和筛选功能的表格。在我们的界面上,将包括一系列的LinkButton ,用于根据用户名首字母筛选显示结果;还有一个GridView 控件,在其中列出相匹配的用户。首先,我们在一个GridView 中列出所有的用户。然后在步骤3 ,我们将加上筛选用的LinkButton 。步骤 4 探讨对筛选结果如何分页。步骤2 到 4 所构建的界面,也将在以后的教程中用到,用于对某一特定用户帐户实施管理。
简介在《为用户指定角色 》教程中,我们建立了一个初级的界面,让管理员选择一个用户并管理他的角色。具体来说,该界面呈现给管理员一个包含所有用户的下拉列表。如果只有十余个用户帐户,这样的界面还比较合适。但对于拥有成百上千个帐户的网站,它就变得非常笨拙了。对于拥有大量用户的网站,一个能分页、能筛选的表格是更适宜的用户界面。 本教程中我们将建立一个这样的用户界面。具体来说,在我们的界面上,将包括一系列的LinkButton ,用于根据用户名首字母筛选显示结果;还有一个GridView 控件,在其中列出相匹配的用户。首先,我们在一个GridView 中列出所有的用户。然后在步骤 3 ,我们将加上筛选用的 LinkButton 。步骤 4 探讨对筛选结果如何分页。步骤 2 到 4 所构建的界面,也将在以后的教程中用到,用于对某一特定用户帐户实施管理。 让我们开始吧 ! 步骤1 :添加新的ASP.NET 页面在本教程和后面两篇教程中,我们将考察各种与管理相关的功能和特性。在这些教程中,我们需要一系列的ASP.NET 页面来完成任务。让我们先创建这些页面并修改站点地图。 首先 , 在项目中创建一个名为 Administration 的新文件夹。 然后,向文件夹中添加两个新的ASP.NET 页面,每个页面都关联到 Site.master 母版页。将这两个页面命名为:
再添加两个页面到网站的根目录下:ChangePassword.aspx 和RecoverPassword.aspx 。 目前,这四个页面上都应该有两个Content 控件,分别占据母版页上的每个 ContentPlaceHolder :MainContent 和 LoginContent 。
对于这些页面的 LoginContent ContentPlaceHolder ,我们想根据母版页默认的标记来显示。所以,清除Content2 的Content 控件的声明标记。做完这件事后,这些页面的标记就应只包含一个Content 控件。 在Administration 文件夹里的ASP.NET 页面只供管理员使用。在《创建和管理角色 》教程中,我们曾将一个Administrators 角色加到系统中,限制这两个页面只允许该角色访问。为此,添加一个Web.config 文件到Administration 文件夹并配置其<authorization> 元素,允许担任Administrators 角色的用户访问,拒绝所有其他用户。
至此,项目的 Solution Explorer 看起来应类似图1 的截屏画面。 图1 :向网站中添加了四个新页面和一个 Web.config 文件(单击此处查看实际大小的图像 ) 最后,修改站点地图 (Web.sitemap) 使其包括一个到ManageUsers.aspx 页面的条目。在我们以前的 Roles 教程中添加的<siteMapNode> 后面,添加下列 XML 标记:
修改站点地图后,打开浏览器访问网站。如图2 所示,左侧的导航中现在包括了 Administration 教程的条目。 图2 :站点地图包括了一个题为 “User Administration” 的节点(单击此处查看实际大小的图像 ) 步骤2 :在一个GridView 中列出所有用户本教程的最终目的,是建立一个可分页、筛选的表格,管理员可以通过它选出一个用户帐户做管理。作为第一步,让我们先在一个GridView 中列出所有用户。这一步完成之后,我们再加入筛选和分页的界面和功能。 打开 Administration 文件夹下的ManageUsers.aspx 页面并加入一个 GridView ,将其 ID 设置为 UserAccounts 。一会儿我们就要写代码,用 Membership 类的GetAllUsers 方法绑定用户帐户集合到该 GridView 。我们在以前的教程中讨论过,GetAllUsers 方法返回一个 MembershipUserCollection 对象,它是 MembershipUser 对象的一个集合。集合中的每个 MembershipUser 都具有 UserName 、Email 、IsApproved 等属性。 为了在该 GridView 中显示我们想要的用户帐户信息,将 GridView 的 AutoGenerateColumns 属性设置为 False ,再用几个 BoundField 显示 UserName 、Email 和Comment 属性,用几个 CheckBoxField 显示 IsApproved 、IsLockedOut 和IsOnline 属性。这些配置可以通过控件的声明标记完成,也可以通过Fields 对话框完成。图 3 显示的是 Fields 对话框的截屏画面,其中 “Auto-generate fields” 复选框未被勾选,并且已经添加并配置好了BoundField 和CheckBoxField 。 图 3 :添加三个 BoundField 和三个 CheckBoxField 到 GridView 中(单击此处查看实际大小的图像 ) 配置好我们的 GridView 以后,声明标记应该如下所示:
然后,我们需要编写代码,将用户帐户绑定到该GridView 。创建一个名为 BindUserAccounts 的方法执行这项任务,并在第一次页面访问时从Page_Load 事件处理程序调用它。
现在 , 我们花点时间打开浏览器测试本页。 如图4 所示,UserAccounts GridView 列出了系统中所有用户的用户名、邮箱地址和其他有关帐户信息。 图4 :GridView 中列出了用户帐户(单击此处查看实际大小的图像 ) 步骤3 :通过用户名首字母筛选显示结果目前,在 UserAccounts GridView 中显示的是所有用户。对于拥有成百上千个用户帐户的网站,很有必要让操作者能很快地削减显示的用户数。在页面中加入筛选用的LinkButton 可以实现这一功能。我们在该页面中加入27 个LinkButton :一个标为 “All” ,其他每个 LinkButton 对应字母表中的一个字母。如果访问者单击“All” LinkButton ,在GridView 中将显示所有用户。如果他单击某一字母,则只显示用户名首字母是该字母的用户。 我们的第一项任务是加进这 27 个LinkButton 控件。可选方法之一是用声明标记创建这27 个 LinkButton ,每次一个。另一个更灵活的方法是用一个Repeater 控件,在一个 ItemTemplate 上放一个 LinkButton ,然后将筛选选项作为一个字符串数组绑定到该Repeater 。 首先将一个Repeater 控件加到页面上,放在UserAccounts GridView 的上面。将该Repeater 的ID 属性设置为FilteringUI 。配置Repeater 的模板,在其ItemTemplate 上放一个LinkButton ,其Text 和CommandName 属性绑定到当前的数组元素。我们在《为用户指定角色 》教程中了解过,这可以通过Container.DataItem 数据绑定语句来实现。用Repeater 的SeparatorTemplate 在每个字母之间显示一个竖线。
要在该 Repeater 上列出我们想要的筛选选项,需要创建一个名为BindFilteringUI 的方法。确保在第一次加载页面时从 Page_Load 事件处理程序中调用该方法。
该方法将筛选选项指定为字符串数组filterOptions 中的元素。对数组的每个元素,在 Repeater 上都将呈现一个 LinkButton ,其 Text 和 CommandName 属性赋值为数组元素的值。 图 5 显示的是在浏览器上看到的 ManageUsers.aspx 页面。 图5 :在 Repeater 上列出 27 个筛选用的 LinkButton (单击此处查看实际大小的图像 ) 注意 : 用户名可能以任何一个字符打头,包括数字和标点符号。为了看到这些用户帐户,管理员必须单击“All” LinkButton 。或者,您可以加上一个 LinkButton ,返回所有以数字打头的用户帐户。 我将此作为练习留给读者完成。 单击任一筛选用的 LinkButton 都将引发回传,并激发 Repeater 的 ItemCommand 事件;但表格中并没有发生什么变化,这是因为我们还没有编写代码来筛选结果。Membership 类包括一个FindUsersByName 方法 ,它返回与指定的搜索格式相匹配的那些用户帐户。我们可以用该方法检索出用户帐户,他们的用户名首字母是被单击的筛选LinkButton 的 CommandName 所指定的字母。 首先修改 ManageUser.aspx 页的代码文件类,让它包括一个名为UsernameToMatch 的属性。该属性保存回传发来的用户名筛选字符串:
UsernameToMatch 属性保存该值,并用key 值 “UsernameToMatch” 分配到 ViewState 集合里。当读出该属性的值时,它检查在ViewState 集合中是否存在一个值,如果没有,则返回默认值空字符串。UsernameToMatch 属性展示了一个通用的模式,即保存一个值到视图状态,从而属性的任何变化都在回传发生后被保存。有关该模式的更多信息,请参阅Understanding ASP.NET View State 。 然后,修改 BindUserAccounts 方法,不调用Membership.GetAllUsers ,而是调用 Membership.FindUsersByName ,传递 UsernameToMatch 属性和SQL 通配符 % 所组合的值。
要只显示用户名首字母是 “A” 的那些用户,则设置UsernameToMatch 属性为 “A” ,然后调用 BindUserAccounts 。这将导致调用 Membership.FindUsersByName("A%") ,它返回所有用户名首字母是 “A” 的用户。同样,为了返回所有用户,分配一个空字符串到UsernameToMatch 属性,使 BindUserAccounts 方法将调用Membership.FindUsersByName("%") ,它返回所有用户帐户。 为Repeater 的 ItemCommand 事件创建一个事件处理程序。 每当单击一个筛选LinkButton 后便引发该事件,它通过RepeaterCommandEventArgs 对象传递被单击的 LinkButton 的 CommandName 值。我们需要分配适当的值到 UsernameToMatch 属性并调用 BindUserAccounts 方法。如果 CommandName 是“All” ,分配一个空字符串到 UsernameToMatch ,从而显示所有用户。否则,分配 CommandName 的值到UsernameToMatch 。
编写好这些代码以后,就可以测试筛选功能了。当第一次访问该页面时,显示了所有的用户(见前面的图5 )。单击 “A” LinkButton ,这引发一个回传并筛选出结果,只显示用户名首字母是“A” 的用户。 图6 :使用筛选 LinkButton 显示以某字母打头的用户名(单击此处查看实际大小的图像 ) 步骤4 :在GridView 使用分页图 5 和图6 中的 GridView 列出了由 FindUsersByName 方法返回的所有用户。如果有几百或几千个用户帐户,当想要查看所有用户时(如单击了“All” LinkButton 或初次访问页面时),就会导致信息超载。为了让用户帐户更易于管理地分块显示,我们配置该GridView ,让它一次只显示 10 个用户。 GridView 控件有两种分页方式:
如果是对几千条记录做分页,默认和定制的分页方式在实现方法上的不同就会变得相当重要了。因为我们建立的该界面假定是有几百或几千个用户帐户,所以我们使用定制的分页方式。 注意 : 有关默认和定制分页方式之间区别的更全面的讨论,以及实现定制分页的难点,请参阅《对大量数据进行高效分页 》教程。有关对默认和定制分页方式在实现方法上区别的分析,参阅Custom Paging in ASP.NET with SQL Server 2005 。 要实现定制分页,我们首先需要一种机制,能选出适合在GridView 中显示的记录的子集。好消息是 Membership 类的 FindUsersByName 方法有一个重载,让我们能够指定页索引和页面大小,并只返回属于记录范围之内的用户帐户。 特别是,该重载有下列签名:FindUsersByName(usernameToMatch, pageIndex, pageSize, totalRecords) 。 其中 pageIndex 参数指定返回用户帐户的哪一页,pageSize 表示每页显示多少条记录。totalRecords 是个输出参数,返回用户库中所有用户帐户的总数。 注意 :FindUsersByName 返回的数据是按用户名排序的,排序标准不能定制。 可以配置 GridView 使用定制的分页,但必须将它绑定到一个ObjectDataSource 控件。让 ObjectDataSource 控件实现定制的分页,需要两个方法:一个方法传递起始行的索引和显示的最大记录数,返回适合在该范围内显示的记录子集;另一个方法返回被分页的记录总数。而FindUsersByName 重载接受页索引和页面大小的值,通过一个输出参数返回记录总数。所以这里有一个接口上的不匹配。 一个方案是创建一个代理类,由它给出ObjectDataSource 所需要的接口,然后内部调用 FindUsersByName 方法。另一个方案(即我们将在本教程使用的)是创建我们自己的分页界面,用来取代GridView 内置的分页界面。 建立一个带First 、Previous 、Next 、Last 的分页界面让我们用 First 、Previous 、Next 和Last 这些 LinkButton 建立一个分页界面。单击 First LinkButton 后,将用户带到数据显示的第一页,而单击Previous 则返回上一页。同样,Next 和 Last 分别将用户带到下一页和最末一页。在UserAccounts GridView 下面加上这四个 LinkButton 控件。
下一步,为每个 LinkButton 的Click 事件创建一个事件处理程序。 图 7 是在Visual Web Developer 的 Design 窗口中看到的这四个 LinkButton 。 图7 :在 GridView 的下面添加First 、Previous 、Next 和 Last LinkButton (单击此处查看实际大小的图像 ) 跟踪当前页面索引当用户第一次访问 ManageUsers.aspx 页,或当他单击了一个筛选按钮后,我们想在GridView 中显示第一页的数据。而当用户单击了一个分页LinkButton 后,我们需要更新页面索引。为保存页面索引和每页显示的记录数,添加下列属性到页面的代码文件类中:
像 UsernameToMatch 属性一样,PageIndex 属性也保存其值到视图状态。只读属性PageSize 返回一个硬编码的值 10 。我邀请有兴趣的读者修改该属性,使用与PageIndex 相同的模式,增加 ManageUsers.aspx 页的功能,让本页的访问者能够指定每页显示多少个用户。 只检索当前页的记录、更新页面索引、启用或禁用分页按钮在安排好分页界面并添加了 PageIndex 和PageSize 属性之后,我们就可以着手修改 BindUserAccounts 方法,让它使用适当的 FindUsersByName 重载。另外,我们还让此方法能够根据目前正在显示哪一页,启用或禁用分页按钮。当正查看第一页数据时,First 和 Previous 按钮应该处于禁用状态;而查看最末一页时,Next 和 Last 应该禁用。 用以下代码修改 BindUserAccounts 方法:
注意,分页查看的记录总数是由FindUsersByName 方法的最后一个参数决定的。这是一个输出参数,所以我们需要首先声明一个变量来存储该值(totalRecords) ,然后用关键词 out 作为它的前缀。 当返回用户帐户的指定页面后,四个LinkButton 是启用还是禁用,取决于正在查看的数据页是否为第一页或最末一页。 最后一步,为四个 LinkButton 的Click 事件处理程序编写代码。这些事件处理程序需要修改PageIndex 属性,然后通过调用 BindUserAccounts 将数据绑定到 GridView 。First 、Previous 和 Next 事件处理程序非常简单。只是 Last LinkButton 的Click 事件处理程序稍微有一点复杂,因为我们为了确定最后一个页索引需要确定一共显示了多少条记录。
图 8 和图9 显示了实际的定制分页界面。图 8 是在 ManageUsers.aspx 页面查看所有用户帐户的第一页数据的情形。注意在总共13 个帐户中只显示了10 个。单击 Next 或 Last 链接将引发一个回传,将 PageIndex 更新为 1 ,并绑定用户帐户的第二页到表格中(见图9 )。 图8 :显示最前面 10 个用户帐户(单击此处查看实际大小的图像 ) 图9 :单击 Next 链接后显示用户帐户的第二页(单击此处查看实际大小的图像 ) 小结管理员经常需要从用户列表中选出一个用户。在以前的教程中我们探讨了用一个下拉列表列出用户,但该方法在用户数量增大时便无法适用。在本教程中我们介绍了一个更好的方法:用一个可筛选的界面,将筛选结果显示在一个分页的GridView 里。使用该用户界面,管理员可以从数千个用户帐户中迅速、有效地定位和选出一个用户。 快乐编程!
|