数据绑定似乎是ASP.NET老掉牙的东西了。可是你知道吗,只需要一点小小的改动就可以替换Eval,摆脱字符串依赖并且大大提高性能。
首先在code behind中加入以下方法
<!-- Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/ -->
protected
virtual
object
ExpHelper
<
TEntity, TREsult
>
(Func
<
TEntity, TREsult
>
func) { var itm
=
GetDataItem();
return
func((TEntity)itm); }
这段代码就是最核心的秘诀了,你完全可以忽视它到底在做什么。其实就是截获每一个被绑定的数据项,并进行强类型转换。
假设我们定义了学生类
<!-- Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/ -->
public
class
Student {
public
string
Name {
get
;
set
; }
public
int
Age {
get
;
set
; } }
如果希望在页面中使用强类型访问学生类而不是用Eval,定义专门访问学生的方法
<!-- Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/ -->
protected
object
Stu
<
TResult
>
(Func
<
Student, TResult
>
func) {
return
ExpHelper
<
Student, TResult
>
(func); }
大功告成,于是在页面里我们就能这样绑定数据了
<!-- Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/ -->
<
ul
>
<
asp:Repeater
ID
="rptStudents"
runat
="server"
>
<
ItemTemplate
>
<
li
><
%#Stu
(_
=>_.Name
+ "(" +_.Age+")")%
></
li
>
</
ItemTemplate
>
</
asp:Repeater
>
</
ul
>
这样做有四大优势
- 得到编译时检测
- 享受智能提示
- 强类型转换比Eval反射性能更高
- 页面中的表示更丰富,如上我们可以自由拼接想要的字符串,非常像MVC
更神奇的是可以支持多层嵌套哦。比如我们定义学生的集合Group类和访问器,然后就能用嵌套的Repeater显示分组信息了。完整程序如下
<!-- Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/ -->
<
%@ Page
Language
="C#"
AutoEventWireup
="true"
%
>
<
script
runat
="server"
>
public class Student { public string Name { get; set; } public int Age { get; set; } } public class Group { public IEnumerable
<
Student
>
Students { get; set; } } protected void Page_Load(object sender, EventArgs e) { //一群学生 var students = new[] { new Student{Name="mike",Age=23}, new Student{Name="jane", Age=12}, new Student{Name="frank",Age=25}, new Student{Name="susan",Age=32}, }; rptStudents.DataSource = students; //分两组 var group0 = new Group(); group0.Students = students.Take(2); var group1 = new Group(); group1.Students = students.Skip(2).Take(2); rptGroups.DataSource = new[] { group0, group1 }; DataBind(); } protected virtual object ExpHelper
<
TEntity
, TREsult
>
(Func
<
TEntity
, TREsult
>
func) { var itm = GetDataItem(); return func((TEntity)itm); } //Student访问器 protected object Stu
<
TResult
>
(Func
<
Student
, TResult
>
func) { return ExpHelper
<
Student
, TResult
>
(func); } //Group访问器 protected object Grp
<
TResult
>
(Func
<
Group
, TResult
>
func) { return ExpHelper
<
Group
, TResult
>
(func); }
</
script
>
<!
DOCTYPE html
>
<
html
>
<
body
>
<
%--
单层--%
>
<
ul
>
<
asp:Repeater
ID
="rptStudents"
runat
="server"
>
<
ItemTemplate
>
<
li
><
%#Stu
(_
=>_.Name
+ "(" +_.Age+")")%
></
li
>
</
ItemTemplate
>
</
asp:Repeater
>
</
ul
>
<
%--
嵌套--%
>
<
ul
>
<
asp:Repeater
ID
="rptGroups"
runat
="server"
>
<
ItemTemplate
>
<
li
>
<
ol
>
<
asp:Repeater
ID
="Repeater1"
runat
="server"
DataSource
='<%#Grp(_=>_.Students) %>'
>
<
ItemTemplate
>
<
li
><
%#Stu
(_
=>_.Name
+ "(" +_.Age+")")%
></
li
>
</
ItemTemplate
>
</
asp:Repeater
>
</
ol
>
</
li
>
</
ItemTemplate
>
</
asp:Repeater
>
</
ul
>
</
body
>
</
html
>
PS
本文是我以前写的没有发表的小发明,现在拿出来晒,主要是因为这个方法好像知道的人很少。希望大家能帮助测试一下性能,如果觉得合适大可以运用到实际工作中。
更新:
感谢Dacey 韦恩卑鄙 dudu老大等人的建议
我已添加了扩展方法版本。喜欢扩展方法这种空降兵的感觉。
现在只要添加一个static的帮助类,名字随你喜欢
<!-- Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/ -->
public
static
class
Helper {
static
object
ExpHelper
<
TEntity, TResult
>
(Page page, Func
<
TEntity, TResult
>
func) { var itm
=
page.GetDataItem();
return
func((TEntity)itm); }
public
static
object
Eval
<
T
>
(
this
Page page, Func
<
T,
object
>
func) {
return
ExpHelper
<
T,
object
>
(page, func); } }
在页面中就可以
<!-- Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/ -->
<
%#this.Eval
<Student
>
(_ => _.Name + "(" + _.Age + ")")%>
- 注意this是必须的
- 扩展方法具有很好的粘合性
- 不需要一个父类定义通用方法
- 泛型提供多个副本并且容易看清类型
- 另外能很好的支持refactor,大家试试用ctrl+r+r改属性名