ListView详解(一)

来源:互联网 发布:淘宝开店后怎么宣传 编辑:程序博客网 时间:2024/05/16 04:56

(原创:灰灰虫的家http://hi.baidu.com/grayworm)


在VS2008中新增了两个非常好用的两个数据控件:ListView和DataPager。使用这两个控件可以很灵活地实现数据的显示、分组、分页、排序、编辑、插入、删除等功能。
在VS2008之前,要显示集合型数据,我们一般会采用Repeater、DataList或GridView等控件来实现。GridView为我们提供了强大的数据显示功能,但是它把界面限制在一个标准的行列Table表格中,比如难以实现在一行显示多条数据的功能;DataList的界面灵活度比GridView要强一些,但使用起来远没有GridView那样简单方便;而Repeater一般是用来显示数据,它内存的事件与模板太少,功能不如DataList强大。ListView兼有GridView的易用性,又拥有DataList的灵活性,是我们DotNew开发的好工具。
签于网上介绍此控件的中文文章太少、太肤浅,在这篇文章中我们来深入研究一下ListView+DataPager的强大功能。

一、ListView初登场
像GridView和DataList等控件都会在显示数据的时候,会自动我们添加一些额外的标记,如:GridView会在未经我们同意的情况下,自动生成<table><tr><td>等元素,并把数据绑定显示在<td>中,虽然可以使用模板列来自定义列的显示,但模板列仍逃不出GridView强行加入的<table>标记,所以GridView做出来的办面往往是规规正正的二维表格,要应对企业开发中的各种表格化界面显得为不从心(虽然GridView也可以实现单元格的合并、GridView的嵌套,但工作量很大,自由度也很受限制)。
ListView在显示数据的时候不会为我们强行添加任何额外的HTML标记,ListView界面的HTML代码完全由开发人员通过以下11个模板来自行控制的。
AlternatingItemTemplate
EditItemTemplate
EmptyDataTemplate
EmptyItemTemplate
GroupSeparatorTemplate
GroupTemplate
InsertItemTemplate
ItemSeparatorTemplate
ItemTemplate
LayoutTemplate
SeletedItemTemplate

其中比较常用的模板有LayoutTemplate和ItemTemplate两个模板,LayoutTemplate用来设置ListView外围的标记,而ItemTemplate是用来生成ListView绑定项的内容。
如:使用ListView显示列表项时,模板代码如下:



《图1 》

从上图我们看出,LayoutTemplate和ItemTemplate分别独立定义,那怎么来把二者进行组合形成一个显示界面呢?我们只需要在LayoutTemplate模板中定义一个“runat=server”的元素,并把这个元素的ID设为ListVieiw控件的ItemPlaceholderID属性所指定的值即可(ListView控件的ItemPlaceholderID属性的默认值为“itemPlaceholder”,如上图中我们定义PlaceHolder的ID就是“itemPlaceholder”。当然我也可以把 PlaceHolder的ID指定为另一个值“aaa”,但需要同时把ListView控件的ItemPlaceholderID的属性设为“aaa”)。
在ListView呈显的时候,就会把LayoutTemplate和ItemTemplate结合起来一起呈现:
首先:用ItemTemplate定义的数据项模板来生成记录项集合



《图2》
然后:再把生成的记录项集合内容替代LayoutTemplate中ID=itemPlacehoder的元素



《图3》

下面我们来试着做个例子显示数据:
在这里我们还是使用“汽车表”作为示例数据。ListView代码如下图所示



《图4》
在这个例子中,我们把ListView控件的ItemPlaceholderID属性修改为“placeForItem”,并在LayoutTemplate模板中把第二<tr>设置为runat="server",并且把该<tr>的ID也设置为“placeForItem”。在ItemTemplate模板中我们从<tr>开始设置模板,在运行的时候会用ItemTemplate生成的数据项(<tr>...</tr>)去替换LayoutTemplate中的<tr runat="server" ID="placeForItem"></tr>
运行结果:



《图5》



《图6》

二、分组显示数据
上面我们使用LayoutTemplate和ItemTemplate实现数据的显示,就是在LayoutTemplate中把要引用ItemTemplate数据项的服务端元素的ID设置为ListView控件的ItemPlaceholderID的值。这种显示方式直接把ItemTemplate生成的内容嵌入到LayoutTemplate中。有的时候这种显示方式不能满足需求,比如:想在一行中显示两项或多项数据的话,上面的方式就无能为力了。



《图7》
要实现上面这种效果就需要使用GroupTemplate模板。
它的实现思想不再是在LayoutTemplate中直接引用ItemTemplate了,而是在LayoutTemplate中引用GroupTempate,在GroupTemplate中再引用ItemTemplate,然后再设置ListView控件的GroupItemCount属性。
在运行的时候,先把ItemTemplate和GroupTemplate整合在一起,然后再根据ListView控件的GroupItemCount属性值,决定每个GroupTemplate中放置几个ItemTemplate。这样我们就可以在LayoutTemplate一行中显示多组数据了。



《图8》
从上面的代码中我们看出,就是在LayoutTemplate和ItemTemplate中间加了一个GroupTemplate。在每个GroupTemplate中显示三个ItemTemplate,然后再把所有GroupTemplate生成的内容嵌入到LayoutTemplate中去。

《图9》

上面的例子我们使用列表项实现分组数据显示,下面我们使用<table>表格实现分组数据的显示。
还是以汽车表为例,我要实现一行显示两辆车的信息。因此我们可以把显示表格设计成这个样子:
<table id="listView">
<tr>
   <td>
    <table id="car">...</table>
   </td>
   <td>
    <table id="car">...</table>
   </td>
</tr>
</table>
外层<table>控制总体部局,外层<tr>控制一行显示几项信息,内层的<table>显示汽车详细信息。
1.ListView控件的GroupItemCount属性设置为2,这就意思着在一个GroupTemplate中显示两个ItemTemplate
2.ItemTemplate中设置如下:
<td>
   <table id="car">...</table>
</td>
3.GroupTemplate设置如下:
<tr>
   <td runat="server" ID="placeForItem"></td>
</tr>
4.LayoutTemplate设置如下:
<table id="listView">
   <tr runat="server" ID="placeForGroup"></tr>
</table>

完整代码如下:



《图10》
运行结果:



《图11》(原创:灰灰虫的家http://hi.baidu.com/grayworm)



《图12》

三、排序数据
有的时候需要我们对数据进行排序显示,比如:论坛中按发表时间排序、按最后回复时间排序、按阅读次数排序、按回复数量排序等。ListView也像GridView一样为我们提供了免编码的排序功能,下面我们来看看:
在这里我们使用SqlDataSource为数据源,还是访问汽车表的数据,关于如何配置SqlDataSource数据源,在这里不再赘述。
我们要实现对两个字段的排序:“价格”和“油耗”
首选来看我们ListView模板的实现:



《图13》
从上图中我们看出,在汽车表格的上面我们加入了两个按钮,这两个按钮都设置了CommandName和CommandArgument。CommandName="Sort"代表这是个排序按钮,当它被点击的时候就会执行Sort()方法进行排序,并触发Sording和Sorted事件。CommandArgument用来指定按哪列排序,在这里我们指定列名。
这样就可以排序了,并且是升序、降序轮流执行的。



《图14》
这种排序功能实用性不大,主要原因是:
1.自动排序只能与DataSource控件结合使用,由DataSource控件排序后再绑定显示在List中,并且ListView排序对DataSource控件返回的数据类型有要求,即,它只能对DataSource控件返回的DataSet、DataTable和DataView进行自动排序,对理一般的泛型集合是不支持的。
2.需要把所有数据都读取到服务器内存(DataSet,DataTable,DataView)中,才能进行排序,资源利用效率不高。

如果要对泛型集合进行排序的话,那需要我们编写Sorting代码,把集合手动排序后再绑定到ListView中显示,同时要通过e.Cancel=true来阻止DataSource控件自动排序。

四、根据字段进行分组显示
上面我们介绍了如何对ListView进行分组,实现一行显示多条数据。但有的时候需要我们进行下面这种分组方式:



《图15》
即:根据某个字段的值不同,对数据分组显示。
ListView默认没有这个功能,但我们可以通过一系列的技巧来实现出来。
实现思路:
第一步、根据需要分组的字段把数据排序,这样就可以把该字段值相同的数据显示为相临的数据行,为我们以后分组提供方便。
这一步我们可以在BLL层中使用LinQ来实现
public class MyDBBF
{
     private MyDBDataContext _Context = new MyDBDataContext();
     public List<Car> GetCars()
     {
         return _Context.Car.OrderBy(p=>p.Brand1.Prod_Code).ToList();
     }
}

第二步、添加分组头。
我们可以在ItemTemplate中,在每次绑定数据行显示之前判断是否需要添加分组头。



《图16》
从上图中我们看到这样一段代码:
<%# ShowGroupHeader() %>
这是我在aspx.cs中定义的一个方法,此方法决定分组头的显示。该方法的代码如下:

《图17》
这个方法在每行绑定的时候都会被调用到
变量headerText代表上一行分组头的文字(即汽车厂商),变量currentHeader代表当前分组字段值,如果二者相等,说明这一行和上一行属于同一个分组,不需要加分组头,就返回空字符串。如果二者不等,说明这一行与上一行不属同一个分组,就添加一个<tr>表头。
第三步、运行。
运行效果如下:



《图18》
(原创:灰灰虫的家http://hi.baidu.com/grayworm)