XO
这几天难耐入XBox 360的冲动,挣扎了两天,考虑到三红问题,还是再忍忍——反正也忍了这么久了,等带HDMI的新版出来后看质量(和刷机方法)再决定吧。:(

这几天难耐入XBox 360的冲动,挣扎了两天,考虑到三红问题,还是再忍忍——反正也忍了这么久了,等带HDMI的新版出来后看质量(和刷机方法)再决定吧。:(

ListView是ASP.NET 3.5新提供的一个控件,它支持GridView类似的功能,并将HTML渲染的责任交由使用者来把控,而这正是GridView的一大劣势(它生成的乱七八糟的HTML输出,即使通过CSS Friendly Control Adapters来净化,也还是让人头痛得不行)。使用ListView两周以来,我已经没有一丁点儿再次使用GridView的欲望了。
由于VS2008还属于Beta2阶段,关于ListView的文档似乎不大容易找到。ScottGu正在写一个关于ListView的系列文章,不过目前还只完成了第一篇;Rick Strahl写的ListView and DataPager in ASP.NET 3.5较深入地讲述了ListView的一些特性。这两篇文章,是学习ListView很精彩的资料。
本系列文章将通过一个简单的实例,结合我自己使用ListView的情况,展示如何用该控件进行基本的Insert、Edit和Delete操作。
按默认配置,新建一个名为ListViewDemo的ASP.NET Web Site。
为了演示的简单性,我们创建一个数据对象DataEntry,它仅包含名为Name和Value的两个成员:
为了方便在演示页面每次PostBack的时候获取数据对象列表,我们会把数据对象列表存放在Session中,所以为DataEntry类设置上Serializable属性。获取数据对象列表的逻辑很简单,从Session里取得,如果为空则进行简单的初始化,非空则直接返回使用:
在页面上添加一个ListView。为其编写LayoutTemplate,使用ul作为输出数据的HTML空器,而每一条数据将使用li来组织。ListView通过将数据输出至ItemContainer来渲染结果。我们在LayoutTemplate中添加一个PlaceHolder作为ItemContainer,这样生成的HTML中不会有任何多余的元素(比方说,如果使用Panel,则会生成一个空的div)。将ListView的ItemContainerID属性设置为这个PlaceHolder的ID:
然后编写ItemTemplate,将每一个数据对象的Name和Value值输出到一个li中:
在Page_Load方法中为ListView绑定上面编写的数据源:
运行该网站工程,显示效果如下:
ListView的Insert Mode通过其属性InsertItemPosition来控制,该属性的取值有三种:
我们先添加一个InsertItemTemplate,在里边放置两个TextBox用于接收Name和Value的用户输入,以及一个Save按钮:
Save按钮的CommandName设置为Insert,这样当用户保存新添加的数据时,Insert相应的事件会被触发。
然后,我们在LayoutTemplate中添加一个New按钮,并将其CommandName设为Create。因为当ListView中数据为空时,不显示LayoutTemplate而是显示EmptyDataTemplate,我们再编写一个EmptyDataTemplate,并在它下面也放一个New按钮。这样当数据被删光时,不至于没有New按钮可用:P
我们为New按钮的CommandName设置了Create值。现在为ListView添加ItemCommand的事件处理方法,然后在里边处理New按钮单击事件,将ListView切换至Insert状态:
注:BindData仅仅是对ListView控件重新进行数据源绑定。
为ListView添加ItemInserting事件处理方法,当Save按钮点击时,在这个方法内处理新数据保存的逻辑。这里遇到一个问题,在这个事件中,如何去获取用户输入的数据?我想ASP.NET应该有很方便又优雅的机制来实现这个功能,比方说这个事件的参数ListViewInsertEventArgs中有一个Values的属性,貌似是用来存储这些数据的。不过我没有弄明白怎使用么用这个属性,只好用土办法来解决:ListViewInsertEventArgs参数中的Item属性以及ListView控件的InsertItem属性,均是当前要插入的Template Item,我们用FindControl方法来获取输入控件并取值保存。保存完毕后,将ListView的InsertItemPosition属性设为None以退出Insert状态:
运行网站测试一下,功能正常:
ListView的Insert功能已经实现。在下一篇里,我们将实现Edit功能。
To be continued…
你开发中的令人心动的Web2网站的底层数据库中有一张用户表,为了与时俱进,你决定用.NET 3.5呀、LINQ什么的来开发。
在实现自己的MembershipProvider的时候,你发现需要实现依据电子邮件或用户名来查找用户的功能,所以你啪嗒啪嗒地敲出了以下代码:
public User FindByEmail(string email)
{
CoolWeb2DataContext db = new CoolWeb2DataContext();
var user = db.Users.SingleOrDefault(u => u.Email == email);
return user;
}
使用Paste & Copy大法,另一个方法呼之即来:
public User FindById(int id)
{
CoolWeb2DataContext db = new CoolWeb2DataContext();
var user = db.Users.SingleOrDefault(u => u.UserId == id);
return user;
}
正打算沾沾自喜时,作为一名正在学习重构的用功的程序员,你发现这两段代码有臭臭的重复的味道。将来网站做大了,可能还要实现FindByAge、FindByMSN、FindByQQ等等方法,你可不想每次拷来拷去把相同的逻辑复制多份,毕竟这年头,代码的价值与LOC是不成正比的。
所以,你打算实现一个通用的Find方法:
private User Find(what?)
{
User = ...;
return user;
}
你注意到要完成这个伟大的算法,需要告诉它你是要查找一个User类型的对象,并且需要把查找的逻辑给传递进去。马上打开.NET类库寻找,很快就找到了这个东东:
public delegate TResult Func(T arg);
嗯,这正是我需要的。你嘀咕着,同时把这个Find方法改为:
private User Find(Funcbool> predicate)
{
CoolWeb2DataContext db = new CoolWeb2DataContext();
var user = db.Users.SingleOrDefault(predicate);
//eh, 也许该作些判空什么的事,还是留到用户数上百万再说吧
return user;
}
这下,原来的两个方法都清爽了:
public User FindByEmail(string email) { return Find(u => u.Email == email); } public User FindById(int id) { return Find(u => u.UserId == id); }
离这个要轰动全球的网站的发布,又进了一大步,再完成99.7%的代码,就可以Beta了。把代码签入,你开心地吃晚饭去了。
Archives: Monthly or