回带来的是 jquery uiRepeater, 在 JQueryElement 最新发布的 3.1 版本中, 对 Repeater 进行了增强, 除了获取数据还实现了更新删除和新建行的功能.

因为篇幅和时间的关系, 本次先介绍一个无刷新获取分页数据的例子. 在例子中, 页面通过 ajax 调用 WebService 方法 Fill 获取分页后的学生数据并绑定.

次的例子只有一个页面 Student.aspx, 如下:

 1 <%@ Page Language="C#" AutoEventWireup="true" CodeFile="Student.aspx.cs" Inherits="_3_Student" %>
2
3 <%@ Register Assembly="zoyobar.shared.panzer.JQueryElement" Namespace="zoyobar.shared.panzer.ui.jqueryui"
4 TagPrefix="je" %>
5 <%@ Register Assembly="zoyobar.shared.panzer.JQueryElement" Namespace="zoyobar.shared.panzer.web.jqueryui"
6 TagPrefix="je" %>
7 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
8 <html xmlns="http://www.w3.org/1999/xhtml">
9 <head runat="server">
10 <title>学生一览</title>
11 <link type="text/css" rel="stylesheet" href="../css/smoothness/jquery-ui-1.8.15.custom.css" />
12 <script type="text/javascript" src="../js/jquery-1.6.2.min.js"></script>
13 <script type="text/javascript" src="../js/jquery-ui-1.8.15.custom.min.js"></script>
14 <link type="text/css" rel="stylesheet" href="../css/main.css" />
15 </head>
16 <body>
17 <form id="formStudent" runat="server">
18 <input type="hidden" id="pi" value="1" />
19 <div class="title">
20 学生一览
21 </div>
22 <div class="content">
23 <je:Button ID="cmdPrev" runat="server" IsVariable="true" Label="上一页" Click="
24 function(){
25 var index = new Number(document.getElementById('pi').value);
26
27 document.getElementById('pi').value = index - 1;
28 studentRepeater.__repeater('fill');
29 }
30 ">
31 </je:Button>
32 <je:Button ID="cmdNext" runat="server" IsVariable="true" Label="下一页" Click="
33 function(){
34 var index = new Number(document.getElementById('pi').value);
35
36 document.getElementById('pi').value = index + 1;
37 studentRepeater.__repeater('fill');
38 }
39 ">
40 </je:Button>
41 <div id="list">
42 </div>
43 </div>
44 <je:Repeater ID="studentRepeater" runat="server" IsVariable="true" Selector="'#list'"
45 Field="['id','realname','age','skill']" Attribute="['pageindex','pagecount','itemcount']" Header='<table><tr class="table-header"><td>姓名</td><td>年龄</td><td>特长</td></tr>'
46 Footer='<tr class="table-footer"><td colspan="3"><span id="result">第 @:pageindex/@:pagecount 页, @:itemcount 条</span></td></tr></table>' Item='<tr class="table-body"><td>#:realname</td><td>#:age</td><td>#:skill</td></tr>' Filled="
47 function(tag, e){
48
49 if(e.data.pageindex == 1)
50 cmdPrev.button('disable');
51 else
52 cmdPrev.button('enable');
53
54 if(e.data.pageindex == e.data.pagecount)
55 cmdNext.button('disable');
56 else
57 cmdNext.button('enable');
58
59 }
60 ">
61 <FillAsync Url="Student.aspx" MethodName="Fill">
62 <ParameterList>
63 <je:Parameter Name="pageIndex" Type="Selector" Value="'#pi'" />
64 </ParameterList>
65 </FillAsync>
66 </je:Repeater>
67 </form>
68 </body>
69 </html>
70 <script type="text/javascript">
71 $(function () {
72 studentRepeater.__repeater('fill');
73 });
74 </script>

  同样是老样子, 开始处引用了 JQueryElement 所需的命名空间以及 jquery ui 所需的脚本和样式.

<%@ Register Assembly="zoyobar.shared.panzer.JQueryElement" Namespace="zoyobar.shared.panzer.ui.jqueryui" TagPrefix="je" %>
<%@ Register Assembly="zoyobar.shared.panzer.JQueryElement" Namespace="zoyobar.shared.panzer.web.jqueryui" TagPrefix="je" %>

 

<link type="text/css" rel="stylesheet" href="../css/smoothness/jquery-ui-1.8.15.custom.css" />
<script type="text/javascript" src="../js/jquery-1.6.2.min.js"></script>
<script type="text/javascript" src="../js/jquery-ui-1.8.15.custom.min.js"></script>

首先看页面中的 Repeater 控件, Selector 属性设置为了 '#list', 那么页面上的元素 <div id="list"></div> 将被设置成为一个浏览器端的 repeater.

Header, Footer, Item 三个属性, 分别表示 repeater 的头模板, 尾模板以及每一行数据对应的行模板. 它们的值是一些的 html 代码, 在这些 html 代码中不应该使用单引号, 因此我们使用了双引号, 而属性本身我们使用单引号括住.

另外, 我们还看到模板 html 代码的一些特殊内容, #:realname, #:age, 这些符号表示绑定字段的操作, 形式为 #:<字段名>. @:pageindex, @:pagecount 则是对属性的绑定, 形式为 @:<属性名>. 以上所说的字段和属性都是来自服务器返回到浏览器端的 json. 稍后会在 Fill 方法中解释. 而 FieldAttribute 表示了参与绑定的字段和属性, 是一个 javascript 形式的字符串数组, 只有在 FieldAttribute 中指定的字段或属性才能够最终参与绑定.

RepeaterFilled 属性是表示 repeater 填充完数据之后的事件, 事件的参数 e.data 也是对应了服务器返回的 json. 我们通过 json 中包含的当前页码 pageindex 和总的页数 pagecount 来判断下一页和上一页按钮是否可用.

最后是 FillAsync 属性, 在这个属性中设置 repeater 调用页面 Student.aspx WebService 方法 Fill 来获取分页数据, 并向方法传递参数 pageIndex, 参数的值取自隐藏元素 <input type="hidden" id="pi" value="1" /> 的值, 默认为第一页, Type 分别表示 Value 是一个表达式还是选择器, 之前的文章也提到过, 这里不再讲述.

<je:Repeater ID="studentRepeater" runat="server" IsVariable="true" Selector="'#list'"
Field
="['id','realname','age','skill']" Attribute="['pageindex','pagecount','itemcount']" Header='<table><tr class="table-header"><td>姓名</td><td>年龄</td><td>特长</td></tr>'
Footer='
<tr class="table-footer"><td colspan="3"><span id="result">第 @:pageindex/@:pagecount 页, @:itemcount 条</span></td></tr></table>' Item='<tr class="table-body"><td>#:realname</td><td>#:age</td><td>#:skill</td></tr>' Filled="
function(tag, e){

if(e.data.pageindex == 1)
cmdPrev.button('disable');
else
cmdPrev.button('enable');

if(e.data.pageindex == e.data.pagecount)
cmdNext.button('disable');
else
cmdNext.button('enable');

}
">
<FillAsync Url="Student.aspx" MethodName="Fill">
<ParameterList>
<je:Parameter Name="pageIndex" Type="Selector" Value="'#pi'" />
</ParameterList>
</FillAsync>
</je:Repeater>

页面还包含了下一页的按钮, 在按钮的 Click 事件中, 我们获取了页面上包含页码的隐藏值, 页码加 1 后重新设置到隐藏值中, 然后我们通过 <Repeater 控件的 ID>.__repeater('fill'); 这样的形式调用 repeater 的 fill 方法, 来进行数据的重新获取和填充. 而上一页按钮和下一页按钮的不同是页码减 1.

<je:Button ID="cmdNext" runat="server" IsVariable="true" Label="下一页" Click="
function(){
var index = new Number(document.getElementById('pi').value);

document.getElementById('pi').value = index + 1;
studentRepeater.__repeater('fill');
}
"
>

当然, 在页面的最后, 我们书写了一段 javascript, 让 repeater 进行第一次填充, 调用的方法和刚才按钮中的一样.

<script type="text/javascript">
$(
function () {
studentRepeater.__repeater(
'fill');
});
</script>

面是 Student.aspx 对应的 Student.aspx.cs 文件, 而代码中需要的 Access 2007student.accdb 和其对应的数据集 StudentDS.xsd 分别放置于 App_DataApp_Code 中:

和上次文章中讲到的一样, 我们使用 WebMethod 来标记 Fill 方法, 使此方法可以作为 WebService 的方法被 ajax 调用. 参数 pageIndex 对应上面的 Repeater 控件的 Parameter.

对于 Fill 方法如何从 Access 中获取的分页数据, 在于使用的 sql 语句, 这里不再讲解, 留给大家慢慢分析吧!

这里要讲的是 Fill 方法返回的类型, 此次示例是在 .NET 4.0 下运行的, 我们看到方法的结尾处返回了一个 new {<属性名>=<属性值>} 形式的匿名类型. .NET 4.0 将这个匿名类型自动的转化为对应的 json 形式, 而省去了我们的麻烦, 好事!!! 在方法结束的位置, 我在注释中写了一个可能的转化后 json 的形式.

在返回的 json 中, __success 表示执行方法是否成功, rows 包含了返回的学生, 这两个属性名称是不能改变的, 而 pageindex, pagecount, itemcount 表示当前页码, 总页数, 总条数, 它们的名称是可以改变的, 只要和前台的绑定一致即可.

 1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Web;
5 using System.Web.UI;
6 using System.Web.UI.WebControls;
7
8 using System.Web.Services;
9 using System.Data;
10 using System.Data.OleDb;
11
12 using StudentDSTableAdapters;
13
14 public partial class _3_Student : System.Web.UI.Page
15 {
16
17 protected void Page_Load ( object sender, EventArgs e )
18 {
19
20 }
21
22 [WebMethod ( )]
23 public static object Fill ( int pageIndex )
24 {
25 int beginIndex = ( pageIndex - 1 ) * 3 + 1;
26 int endIndex = pageIndex * 3;
27
28 string command = string.Format ( "select ID, RealName, Age, Skill from (select ID, RealName, Age, Skill, (select count(*) from Student where ID <= X.ID) as RN from Student as X order by ID asc) as Y where RN >= {0} and RN <= {1}", beginIndex, endIndex );
29
30 OleDbDataAdapter adapter = new OleDbDataAdapter ( command, @"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=|DataDirectory|\student.accdb;Persist Security Info=True" );
31
32 StudentDS.StudentDataTable table = new StudentDS.StudentDataTable ( );
33 adapter.Fill ( table );
34
35 command = "select count(*) as C from Student";
36 adapter = new OleDbDataAdapter ( command, @"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=|DataDirectory|\student.accdb;Persist Security Info=True" );
37 DataTable countTable = new DataTable ( );
38 adapter.Fill ( countTable );
39
40 int count = Convert.ToInt32 ( countTable.Rows[0][0] );
41
42 List<object> students = new List<object> ( );
43
44 foreach ( StudentDS.StudentRow row in table )
45 students.Add ( new { id = row.ID, realname = row.RealName, age = row.Age, skill = row.Skill } );
46
47 return new { __success = true, rows = students.ToArray ( ), itemcount = count, pageindex = pageIndex, pagecount = ( int ) Math.Ceiling ( ( decimal ) count / ( decimal ) 3 ) };
48 /*
49 * {
50 * "__success": true,
51 * "rows":
52 * [
53 * { "id": 1, "realname": "...", "age": 10, "skill": "..." },
54 * { "id": 2, "realname": "...", "age": 20, "skill": "..." }
55 * ],
56 * "itemcount": 7,
57 * "pageindex": 1,
58 * "pagecount": 3
59 * }
60 * */
61 }
62
63 }

终, 我们实现了一个说的过去的无刷新的分页功能, 至于 Repeater 的更新修改删除功能, 下期再讲吧.

JQueryElement 是开源共享的代码, 可以在 http://code.google.com/p/zsharedcode/wiki/Download 页面下载 dll 或者是源代码.

目前 JQueryElement 最新版本为 3.1, 可以在上面的地址看到新版本改动的内容.

示例代码下载: http://zsharedcode.googlecode.com/files/JQueryElementTest.rar.

实际过程演示: http://www.tudou.com/programs/view/eZbcCKp2GNU/ .

作者: 麦丝平方 发表于 2011-08-25 16:05 原文链接

推荐.NET配套的通用数据层ORM框架:CYQ.Data 通用数据层框架
新浪微博粉丝精灵,刷粉丝、刷评论、刷转发、企业商家微博营销必备工具"