相关文章:强类型ASP.NET数据绑定改进版、强类型ASP.NET数据绑定改进版之第2版
数据绑定似乎是ASP.NET老掉牙的东西了。可是你知道吗,只需要一点小小的改动就可以替换Eval,摆脱字符串依赖并且大大提高性能。
首先在code behind中加入以下方:
protected
virtual
object
ExpHelper
<
TEntity, TREsult
>
(Func
<
TEntity, TREsult
>
func)
{
var itm = GetDataItem();
return func((TEntity)itm);
}
{
var itm = GetDataItem();
return func((TEntity)itm);
}
这段代码就是最核心的秘诀了,你完全可以忽视它到底在做什么。其实就是截获每一个被绑定的数据项,并进行强类型转换。
假设我们定义了学生类:
public
class
Student
{
public string Name { get ; set ; }
public int Age { get ; set ; }
}
{
public string Name { get ; set ; }
public int Age { get ; set ; }
}
如果希望在页面中使用强类型访问学生类而不是用Eval,定义专门访问学生的方法:
protected
object
Stu
<
TResult
>
(Func
<
Student, TResult
>
func)
{
return ExpHelper < Student, TResult > (func);
}
{
return ExpHelper < Student, TResult > (func);
}
大功告成,于是在页面里我们就能这样绑定数据了:
<
ul
>
< asp:Repeater ID ="rptStudents" runat ="server" >
< ItemTemplate >
< li >< %#Stu (_ =>_.Name + "(" +_.Age+")")% ></ li >
</ ItemTemplate >
</ asp:Repeater >
</ ul >
< asp:Repeater ID ="rptStudents" runat ="server" >
< ItemTemplate >
< li >< %#Stu (_ =>_.Name + "(" +_.Age+")")% ></ li >
</ ItemTemplate >
</ asp:Repeater >
</ ul >
这样做有四大优势:
- 得到编译时检测
- 享受智能提示
- 强类型转换比Eval反射性能更高
- 页面中的表示更丰富,如上我们可以自由拼接想要的字符串,非常像MVC
更神奇的是可以支持多层嵌套哦。比如我们定义学生的集合Group类和访问器,然后就能用嵌套的Repeater显示分组信息了。完整程序如下:
<
%@ 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 >
< 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的帮助类,名字随你喜欢:
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);
}
}
{
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);
}
}
在页面中就可以:
<
%#this.Eval
<Student
>
(_ => _.Name + "(" + _.Age + ")")%>
- 注意this是必须的。
- 扩展方法具有很好的粘合性。
- 不需要一个父类定义通用方法。
- 泛型提供多个副本并且容易看清类型。
- 另外能很好的支持refactor,大家试试用ctrl+r+r改属性名。