在asp.net中我们知道有viewstate这样的页面级容器为我们保存表单数据,这样我们每次提交时数据都不会丢失,很容易的完成查询+分页的实现。找过相关MVC分页的例子,都是扩展HtmlHelper方法来实现。我想大家在ASP.NET开发中都用过 wuqi的AspNetPager分页控件以及dacey的NSunPage用来开发Winform项目的分页控件非常方便的满足了大家的分页需求。那么我们来看下在MVC中的查询+分页是怎么实现的。(这里我用到了wuqi的mvcpager)
下面例子是asp.net中的分页查询:
前台代码:
<
html
>
<
body
>
<
form
id
="form1"
runat
="server"
>
部门编号:
<
asp:TextBox
ID
="deptcode"
Width
="80px"
runat
="server"
></
asp:TextBox
>
部门名称:
<
asp:TextBox
ID
="deptname"
Width
="80px"
runat
="server"
></
asp:TextBox
>
<
asp:Button
ID
="btnquery"
runat
="server"
Text
="查询"
onclick
=" btnquery_Click"
/>
<
table
class
="TableBlock"
width
="100%"
style
="margin-top: 10px;"
>
<
tr
>
<
th
>
编号
</
th
>
<
th
>
名称
</
th
>
</
tr
>
<
asp:Repeater
ID
="TableBlockList"
runat
="server"
>
<
ItemTemplate
>
<
tr
>
<
td
>
<%
#
Eval
(
"
code
"
)
%>
</
td
>
<
td
>
<%
#
Eval
(
"
name
"
)
%>
</
td
>
</
tr
>
</
ItemTemplate
>
</
asp:Repeater
>
</
table
>
</
form
>
</
body
>
</
html
>
后台代码:
protected
virtual
SelectSqlSection GetSelectSearch()
{
SelectSqlSection select
=
db.GetSelectSqlSection ();
if
(
!
string
.IsNullOrEmpty (deptname.Text)) {
select.Where (View_DeptQueryInfo.__name.Like(deptname.Text
+
"
%
"
));
}
if
(
!
string
.IsNullOrEmpty(deptcode.Text)){
select.Where (View_DeptQueryInfo.__code.Like(deptcode.Text
+
"
%
"
));
}
return
select;
}
protected
void
BindTable(Repeater rpt, AspNetPager anp)
{
int
countPage
=
0
;
DataTable dt
=
db.SelectPageToDataTable(GetSelectSearch (), anp.PageSize, anp.CurrentPageIndex,
out
countPage);
anp.RecordCount
=
countPage;
rpt.DataSource
=
dt;
rpt.DataBind();
}
以上就完成了查询分页的功能,没什么特别的和我们做winform的差不多。第二次查询一样能获得表单内的值。
那么asp.net mvc中怎么实现呢?用什么来保存表单数据呢?记得原来写java的时候我是用session这样笨拙的方法来保存查询提交后的方法来保存用户查询条件的。那么在asp.net mvc中我们该怎么实现呢?
页面代码:
<
html
>
<
body
>
<
form
id
="form1"
method
="post"
action
="/Dept/Dept"
runat
="server"
>
部门名称:
<
input
id
="deptname"
name
=" deptname "
type
="text"
value
='<%=ViewData
["deptname "] %
>
'/>
部门编号:
<
input
id
="deptcode"
name
=" deptcode "
type
="text"
value
='<%=ViewData
["deptcode "] %
>
'/>
<
input
id
="btnquery"
type
="submit"
value
="查询 "
/>
<
table
class
="TableBlock"
width
="100%"
>
<
tr
>
<
th
>
编号
</
th
>
<
th
>
部门名称
</
th
>
</
tr
>
<
asp:MvcRepeater
ID
="MvcRepeater1"
Key
="deptlist"
runat
="server"
>
<
ItemTemplate
>
<
tr
>
<
td
style
="width:5;"
>
<%
#
Eval
(
"
code
"
)
%>
</
td
>
<
td
style
="width:10;"
>
<%
#
Eval
(
"
name
"
)
%>
</
td
>
</
tr
>
</
ItemTemplate
>
</
asp:MvcRepeater
>
</
table
>
<
div
class
="pager"
style
="width:100%;text-align:right;"
>
<
div
class
="pager"
align
="left"
style
="float: left; width: 40%;"
>
<%
=
"
共
"
+
((Webdiyer.WebControls.Mvc.PagedList
<
DepartmentInfo
>
)ViewData [
"
deptlist
"
]).TotalPageCount
+
"
页
"
+
((Webdiyer.WebControls.Mvc.PagedList
<
DepartmentInfo
>
)ViewData [
"
deptlist
"
]).TotalItemCount
+
"
条
"
%>
</
div
>
<
div
align
="right"
class
="pager"
style
="width: 60%; float: left;"
>
<%
=
Html.Pager
<
DepartmentInfo
>
((Webdiyer.WebControls.Mvc.PagedList
<
DepartmentInfo
>
)ViewData [
"
deptlist
"
],
new
PagerOptions() { PageIndexParameterName
=
"
id
"
, CurrentPagerItemWrapperFormatString
=
"
<span class=\
"
cpb
\
"
> {0}</span>
"
, NumericPagerItemWrapperFormatString
=
"
<span class=\
"
item
\
"
> {0}</span>
"
, CssClass
=
"
pages
"
, SeparatorHtml
=
""
,IsPost
=
true
})
%>
</
div
>
</
div
>
</
form
>
</
body
>
</
html
>
首先用到了Repeater,在mvc中Repeater的使用需要我们重写一下。如果想用for循环来实现也可以。我们继承Repeater然后重写OnLoad(EventArgs e) 方法得到Controller中放入ViewData的数据。我们添加一个公开的属性来取得对应ViewDate的值。
Repeater重写:
public
string
Key {
get
;
set
; }
//
绑定数据
protected
override
void
OnLoad(EventArgs e)
{
this
.DataSource
=
(
base
.Page
as
ViewPage).ViewData[
this
.Key];
this
.DataBind();
base
.OnLoad(e);
}
这样就得到我们想要的
MVC
中的
Repeater
,因为
Repeater
必须放在
runat="server"
的
form
中所以这里
action
没有使用
UrlHepler
给我们提供的方法来写。
我们把查询条件放入
ViewData
为了提交后的保存与显示。
<
input
id
="deptname"
name
=" deptname "
type
="text"
value
='<%=ViewData ["deptname
"] %
>
'/>
后台保存:
public
ActionResult Dept (
int
?
id)
{
ViewData [
"
deptlist
"
]
=
BindTable(id);
return
View();
}
protected
Webdiyer.WebControls.Mvc.PagedList
<
DepartmentInfo
>
BindTable(
int
?
id)
{
int
countPage
=
0
;
List
<
DepartmentInfo
>
dt
=
db.SelectPageToList(GetSelectSearch(),
10
, id
??
1
,
out
countPage);
Webdiyer.WebC ontrols.Mvc.PagedList
<
DepartmentInfo
>
p
=
new
Webdiyer.WebControls.Mvc.PagedList
<
DepartmentInfo
>
(dt, id
??
1
,
10
, countPage);
return
p;
}
protected
virtual
SelectSqlSection GetSelectSearch()
{
SelectSqlSectio n select
=
db.GetSelectSqlSection();
select.OrderBy (DepartmentInfo.__ordernumber.Asc);
if
(
!
string
.IsNullOrWhiteSpace(Request[
"
deptname
"
]))
{
select.Where(DepartmentInfo.__name.Like(
"
%
"
+
GetFormValue(
"
deptname
"
)
+
"
%
"
));
}
if
(
!
string
.IsNullOrWhiteSpace(Request[
"
deptcode
"
]))
{
select.Where(DepartmentInfo.__code.Like(
"
%
"
+
GetFormValue(
"
deptcode
"
)
+
"
%
"
));
}
return
select;
}
private
object
GetFormValue(
string
name)
{
ViewData [name]
=
Request[name];
return
ViewData[name];
}
这里出现问题了,在查询时候的确可以获得表单的值,也可以这样保存显示,那么查询后点分页怎么办?分页可是a标签,难道让a标签也提交么?
OK
,那么我们就来实现
a
标签的提交,我们就来给它分页时做提交功能。
因为每次分页都提交表单可能不是各个场景都需要,这里我对 PagerOptions类扩展了2个属性一个是 ispost(分页是否提交,默认是false) ,FormName(提交表单id,这里默认是 asp.net生成的form1)。
再来看怎么生成控件到页面,我们看PagerBuilder类,找到GeneratePagerElement方法,看最后一句String.Format ("<a href='{0}'>{1}</a>", url, item.Text));默认是生成只带连接的a标签,我们来改造他吧。
我们重新写这个方法名字就叫GeneratePagerElementPost,我们把a 标签的href执行一段脚本,把刚才那句替换为 String.Format("<a href='javascript:_PagePostSubmit (\"{0}\")'>{1}</a>", url, item.Text));
这个js方法 就是用来点击a标签进行表单的提交的。那么我们看这个方法是怎么实现和生成到页面的。找到RenderPager方法,我们拉到方法最后看到如下代码,这里是添加脚本到客户端。
if (!string.IsNullOrEmpty(pagerScript))
pagerScript = "<script language=\"javascript\" type=\"text/javascript\">" + pagerScript + "</script>";
在这个方面上面添加一下代码:首先我们判断下客户端是否需要每次分页都提交页面,然后加入我们的_PagePostSubmit这个js方法
if (_pagerOptions.IsPost)
{
//通过 _pagerOptions.FormName获得用户选定表单名称,修改其 action,然后提交。
pagerScript += " function _PagePostSubmit(href){ document.forms['" + _pagerOptions.FormName + "'].action=href;document.forms['" + _pagerOptions.FormName + "'].submit();}";
}
Ok,这样每个 a标签都能提交表单了,我们在页面添加下面代码就完成了查询+分页的实现
<%
=
Html.Pager
<
DepartmentInfo
>
((Webdiyer.WebControls.Mvc.PagedList
<
DepartmentInfo
>
)ViewData [
"
deptlist
"
],
new
PagerOptions() { PageIndexParameterName
=
"
id
"
, CurrentPagerItemWrapperFormatString
=
"
<span class=\
"
cpb
\
"
> {0}</span>
"
, NumericPagerItemWrapperFormatString
=
"
<span class=\
"
item
\
"
> {0}</span>
"
, CssClass
=
"
pages
"
, SeparatorHtml
=
""
,IsPost
=
true
})
%>
把刚加的 IsPost属性变为 true,默认FormName=form1这里就没有在赋值了。
实现DEMO:ASP.NET MVC查询+分页 DEMO
修改后的MVCPAGER: ModifyPostMvcPagerSrc