`

扩展GridView控件以包含一个与排序相关的箭头标记

阅读更多

本文英文原版及代码下载:
http://aspnet.4guysfromrolla.com/articles/012308-1.aspx

扩展GridView控件以包含一个与排序相关的箭头标记

导言:

在ASP.NET 2.0发表之前,我针对DataGrid控件写了一本书以及许多的文章,虽然DataGrid依然存在于ASP.NET 2.0里,但相较而言GridView控件提供了更多的功能及特性.它可以绑定到象SqlDataSource和ObjectDataSource这样的数据源控件, 不用手写代码我们就可以执行排序、分页、编辑、删除等功能.

虽然DataGrid (以及GridView)支持内置的排序功能,但我们无法从感官上判断是按哪一列来进行排序的.在系列文章的Part 18部分《An Extensive Examination of the DataGrid Web Control》,我们看到了如何对一个支持排序的DataGrid的表头列进行update,当依据某个列进行升序或降序排序操作时,在该列上显示一个向上或向下的箭头标记.实现方法是这样的,遍历DataGrid控件的Columns collection,当该列的SortExpression值与DataGrid控件的SortExpression相匹配时,就对该列添加相应的箭头标记.


图1

我最近需要在一个GridView控件上实现该功能。与DataGrid示例不同,我不打算在ASP.NET页面里添加代码,而是重新创建一个自定义Web server控件,来对GridView进行扩充,并添加必要的functionality.在本文,我们将探讨具体的操作步骤,以及如何在ASP.NET页面里使用该控件.相关示例代码在本文结尾处可下载.

GridView Sorting简述

GridView控件实现排序很简单,只要将AllowSorting属性设置为True即可.这样,它的表头列就呈现为一个LinkButton.当点击后,回传并触发GridView的Sorting event事件.如果GridView绑定的数据源控件支持排序,那么GridView将在内部进行排序以及重新绑定数据.如果是通过编程的方式来将数据绑定到GridView的,那么我们就要为Sorting event事件创建事件处理器,自己写代码实现排序和重新绑定数据.当触发Sorting event事件并重新绑定数据后,接下来GridView就触发Sorted event事件,结束排序流程.

GridView的每列都有一个SortExpression属性,当点击某个列上的 LinkButton时,就指示数据按该列进行排序,同时将GridView的SortExpression属性赋值为该列的SortExpression,再加SortDirection属性,GridView就有了内置的、双向的排序功能.

下面的图解释了排序的流程,包括对SortExpression 和 SortDirection属性赋值.记住,正个流程是从用户点击某个列的LinkButton开始的,当按要求对数据排完序后就结束了.所以,从终端用户的角度来看,当他点击某个表头列的文字后,数据就按照该列进行排序了.


图2

创建一个对GridView进行了扩展的Custom Server Control

在关于DataGrid控件系列文件的Part 18部分,我们将与箭头标记相关的代码放在页面的后台代码类里.具体来说,代码思路是遍历DataGrid的Columns collection,对每列而言,先将出现在HeaderText里的任何<img>元素清除掉,这样就把所有列里的箭头图片都抹去了.然后,代码检查当前列的SortExpression是否与DataGrid控件的SortExpression值相匹配,如果是的话,就把相应的向上或向下的箭头标记添加到该列的HeaderText的尾部.

类似的,GridView也有一个Columns collection;每列也有一个SortExpression;也有SortExpression 和 SortDirection属性.换句话说,要对GridView添加箭头标记的话,我们可以象操作DataGrid那样来进行。不过在此,我打算创建一个对GridView进行了扩展的custom server control,添加必要的代码来对必要的方法进行重写.

为此,我们要创建一个继承自Web control的public class来进行扩展.我在名为skmControls的Class Library project里创建了一个名为GridView的类.(在文章《Creating a TextBox Word / Character Counter Control》里我们首先创建并探讨了该skmControls2 Class Library project)

public class GridView : System.Web.UI.WebControls.GridView
{
... Override necessary GridView methods here ...
}

GridView有一个虚方法,virtual InitializeRow method.每次向GridView添加一row时都会调用该方法,包括header row.我最先想到的是重写该方法,对header row而言,遍历所有的列(field),并每列的HeaderText适当更新 (也就是先移除所有的image标记,再为那个作为排序依据的列添加恰当的向上或向下的箭头标记).然而,在databinding阶段,如果你尝试更新GridView的field的属性的话,该field将向GridView报告其状态发生了改动,并要求重新绑定数据.这样一来我们就陷入了一个死循环:

1.Databinding开始
2.对header row执行InitializeRow method方法
3.我再对header row里每个单元(cells)的HeaderText进行更新
4.对HeaderText的更新将导致通知GridView重新绑定数据,重新返回到第1步!

因此我们需要在databinding处理过程之前或之后来修改HeaderText属性.几经考虑后,我意识到我只需要在完成了对数据的排序后再修改HeaderText属性.GridView控件的OnSorted method方法将触发Sorted event事件,当然在数据完成了排序之后才会发生该事件.因此,我决定重写该方法,并在该方法里更新HeaderText属性.

public class GridView : System.Web.UI.WebControls.GridView
{
protected override void OnSorted(EventArgs e)
{
string imgArrowUp = ...;
string imgArrowDown = ...;

foreach (DataControlField field in this.Columns)
{
// strip off the old ascending/descending icon
int iconPosition = field.HeaderText.IndexOf(@" <img border=""0"" src=""");
if (iconPosition > 0)
field.HeaderText = field.HeaderText.Substring(0, iconPosition);

// See where to add the sort ascending/descending icon
if (field.SortExpression == this.SortExpression)
{
if (this.SortDirection == SortDirection.Ascending)
field.HeaderText += imgArrowUp;
else
field.HeaderText += imgArrowDown;
}
}

base.OnSorted(e);
}
}

经过重写的该OnSorted method方法首先为向上和向下的箭头图标指定URL,我们将在后面详细探讨.接下来,对GridView的Columns collection遍历,将每列的<img>元素删除.再接下来,检查当前列的SortExpression是否与GridView的SortExpression匹配,如果匹配的话,根据GridView的 SortDirection属性的值,HTML将把向上或向下的箭头标记显示在该列的HeaderText里.

一个有关HTML Encoding的问题

我在测试的时候发现一个问题,在默认的情况下,BoundField HTML会对其HeaderText的内容进行encode处理.换句话说,在处理BoundField输出时,OnSorted method方法把<img>标签添加到BoundField,而HTML又对其进行encode处理,分别把 < 和 > 替换为&lt 和 &gt;也就是说,它将一个HeaderText值

Price <img border="0" src="up.gif" />
转换为
Price &lt;img border="0" src="up.gif" /&gt

因此浏览器呈现的是:Price <img border="0" src="up.gif" />,而不是我们期望的一个图标.

BoundField有一个HtmlEncode属性,默认为True,这样HTML就把BoundField包含的整个内容进行编码处理.因此我们想到的是将HtmlEncode属性设置为False,但如果我们只是不希望对表头进行HTML encode处理,而对data row依然进行HTML encode,哪又怎么办呢?

为此,我在skmControls2 project里创建了另一个自定义类,该类继承自BoundField class,重写了InitializeCell method方法,而HTML encode就是发生在这个方法里的.只有当BoundField的HtmlEncode 和 SupportsHtmlEncode属性都为True时,才会对其内容进行HTML encode处理.另外,SupportsHtmlEncode属性是只读的,对BoundField而言,总是返回 True.因此我重写了SupportsHtmlEncode属性,它根据一个私有成员变量返回一个值.这样一来,当初始化一个表头单元(header cell)时,在重写的这个InitializeCell method方法里,我将该私有成员变量设置为false.

public class BoundField : System.Web.UI.WebControls.BoundField
{
bool allowHtmlEncode = true;

protected override bool SupportsHtmlEncode
{
get
{
return allowHtmlEncode;
}
}

public override void InitializeCell(DataControlFieldCell cell, DataControlCellType cellType, DataControlRowState rowState,

int rowIndex)
{
if (this.HtmlEncode && cellType == DataControlCellType.Header)
{
allowHtmlEncode = false;
base.InitializeCell(cell, cellType, rowState, rowIndex);
allowHtmlEncode = true;
}
else
base.InitializeCell(cell, cellType, rowState, rowIndex);
}
}

在所有的GridView field里,只对BoundField的数据进行HTML encode处理,所以上述的处理是专门针对BoundField而言的.对其它的TemplateField, CheckBoxField, ButtonField等而言,我们不用进行额外的处理就可以准确无误的添加箭头标记.为向上或向下的箭头指定Image URLs

那么如何为箭头图标指定URL呢?我为此创建了2个属性,ArrowUpImageUrl 和 ArrowDownImageUrl;当然如果开发人员嫌麻烦的话,也可以将这2个箭头图片镶嵌在skmControls2装配件里.当开发人员没有为ArrowUpImageUrl 和 ArrowDownImageUrl指定值时,这是很有用的.

关于如何将资源(resources)镶入装配件,以及在一个ASP.NET页面里检索这些资源,请参阅文章《Accessing Embedded Resources through a URL Using WebResource.axd》

在ASP.NET页面里使用该自定义GridView控件

在文章结尾处可下载到本文所用代码,要使用该skmControls2控件,将DLL拷贝到 website的/Bin目录,再在要使用该控件的.aspx页面添加如下的@Register声明:

<%@ Register Assembly="skmControls2" Namespace="skmControls2" TagPrefix="skm" %>


另外,你还可以在Web.config文件里添加@Register声明,这样你就不用在页面上添加了,具体方法见《Tip/Trick: How to Register User Controls and Custom Controls in Web.config》

象使用普通GridView控件那样来使用,只不过将<asp:GridView>标签里的"asp"替换成"skm", 象这样<skm:GridView>,就这么简单!同样的,对BoundFields,你替换为 <skm:BoundField>代码里有个页面从Northwind数据库的Products数据库表里将ProductID, ProductName, CategoryName, UnitPrice,以及Discontinued列显示在一个支持排序的GridView控件里,用的了一个TemplateField,一个CheckBoxField,以及多个BoundFields(也就是skmControls2 BoundFields).如下:

<skm:GridView ID="ProductsGrid" runat="server" AutoGenerateColumns="False" DataSourceID="NorthwindDataSource"

AllowSorting="True">
<Columns>
<skm:BoundField DataField="ProductID" HeaderText="ID" InsertVisible="False"
SortExpression="ProductID" />
<asp:TemplateField HeaderText="Name" SortExpression="ProductName">
<ItemTemplate>
<asp:Label runat="server" Text='<%# Bind("ProductName") %>' id="Label1" Font-Bold="True"></asp:Label>
</ItemTemplate>
</asp:TemplateField>
<skm:BoundField DataField="CategoryName" HeaderText="Category Name" SortExpression="CategoryName" />
<skm:BoundField HtmlEncode="False" DataFormatString="{0:c}" DataField="UnitPrice" HeaderText="Price"

SortExpression="UnitPrice" />
<asp:CheckBoxField DataField="Discontinued" HeaderText="Discontinued" SortExpression="Discontinued" />
</Columns>
</skm:GridView>

注意到我们没有在声明代码里设置ArrowUpImageUrl 或 ArrowDownImageUrl属性的值,因此,方格里使用的是默认提供的向上或向下箭头标记(见下面的第一个截屏).如果你想使用自己提供的箭头图标,那么就要显式的指定URL值,或通过编程来指定.可以是绝对URL(比如:http://www.example.com/images/UpArrow.gif) 或相对路径,比如: ~/Images/UpArrow.png. 在示例页面里包含了一个checkbox,允许你使用默认的或自己提供的箭头图标.

下面的2个截屏是代码演示情况,第一个显示的是按价格的降序排序,当然使用的是内置默认的那个向下箭头图标.


图3

第二个截屏显示的是按产品名称来排序的,不过使用的是自己提供的箭头标记.


图4

当使用Fields Dialog Box时自定义的BoundField Markup会丢失

如果你使用skmControls2 library里的自定义BoundField control的话,比如:<skm:BoundField ... />, 有一点你应该知道,当我们使用Fields dialog box来修改GridView的列时,Visual Studio会自动的把我们自定义的BoundField markup替换成默认的<asp:BoundField ... />.当我们在GridView的智能标签里点击"Edit Columns"时就会弹出Fields dialog box对话框.

结语:

本文我们探讨了如何构建一个自定义GridView server control(以及一个自定义BoundField control),以便展示一个箭头标记.该箭头标记使我们可以清楚的看到是按哪列的升序还是降序来排序的.最好将该功能封装在一个自定义server control里,这样一来我们就不用在ASP.NET页面里写代码就可以实现该功能了.

祝编程快乐!

分享到:
评论

相关推荐

    扩展GridView控件(增加多个常用功能)

    在这个“扩展GridView控件(增加多个常用功能)”的项目中,我们将探讨如何在Visual Studio 2005环境下,通过自定义控件的方式,为GridView添加额外的特性。 首先,我们需要了解GridView的基本结构和工作原理。...

    Gridview控件的使用详解

    GridView 控件的高级技巧包括实现鼠标移到 GridView 某一行时改变该行的背景色、实现删除时弹出确认对话框、实现自动编号等。以下是一些高级技巧: 1. 实现鼠标移到 GridView 某一行时改变该行的背景色:可以通过...

    GridView控件的排序、分页、编辑功能实现实例

    GridView控件的排序、分页、编辑功能实现实例 GridView控件是 ASP.NET 中常用的数据GridView控件,它提供了丰富的功能来展示和操作数据。在本实例中,我们将展示如何实现GridView控件的排序、分页和编辑功能。 ...

    一个含有列过滤的自定义翻页的GridView扩展控件

    1. **扩展GridView控件**:创建一个新的服务器控件,继承自GridView,然后在这个新的控件中添加自定义翻页和列过滤的相关属性和方法。 2. **处理过滤事件**:在列过滤元素(如文本框)的`TextChanged`事件中,获取...

    精致的GridView控件源码

    这款精致的GridView控件源码提供了一种自定义和扩展的可能性,使得开发者可以根据自己的需求对其进行调整,以满足特定的设计和功能需求。 首先,我们来深入了解GridView控件的基本特性。GridView控件是ASP.NET框架...

    查询控件,gridview扩展

    GridView的扩展通常包括自定义分页、排序、筛选和编辑功能。开发者可以通过编写后台代码或使用模板字段来自定义列的显示方式,甚至可以添加行选择、行编辑和行删除等功能。此外,GridView还可以与其他控件(如查询...

    GridView控件的简单使用

    GridView控件是Windows Forms和ASP.NET Web开发中常用的一种数据展示工具,它的核心功能是将数据源中的数据以网格形式进行展示,便于用户查看、编辑和操作数据。在本篇文章中,我们将深入探讨GridView控件的基本用法...

    windows 控件开发典型的GridView控件扩展

    在本主题中,我们将深入探讨“Windows控件开发典型的GridView控件扩展”以及“label控件扩展”,这两个主题对于提升应用程序的用户体验和功能至关重要。 首先,让我们来看看GridView控件。GridView是.NET Framework...

    自定义GridView控件 代码

    在这个场景下,创建一个自定义的GridView控件就显得非常有必要。 首先,我们要理解三层架构的概念。三层架构是一种常见的软件设计模式,它将应用程序分为三个主要层次:表现层(UI)、业务逻辑层(BLL)和数据访问...

    GridView控件

    或者在代码视图中手动添加控件标记。 ```xml &lt;asp:GridView ID="GridView1" runat="server"&gt;&lt;/asp:GridView&gt; ``` 2. 绑定数据源:GridView控件需要数据源才能显示数据。可以通过`DataSource`属性设置数据源,然后...

    ASP.NET初级_GridView控件和FormView控件

    在提供的压缩包"Koko_ASP.NET初级_GridView控件和FormView控件"中,你可能找到一个示例项目,展示了如何在实际开发中使用这两种控件。通过研究这个例子,你可以学习如何设置控件属性,编写事件处理程序,以及如何在...

    ASP的GridView控件类

    ASP的GridView控件类是ASP开发中的一个核心组件,它为网页展示数据提供了一种强大的方式。这个控件类似于ASP.NET中的GridView,允许开发者以表格形式动态地显示来自数据库或其他数据源的数据。在本文中,我们将深入...

    GridView控件用法Demo

    这个"GridView控件用法Demo"压缩包提供了一个全面的学习资源,包括各种示例和源代码,对于学习和掌握GridView的使用非常有帮助。 1. **GridView简介**: GridView是一个服务器端控件,用于显示数据源中的数据,如...

    gridview控件使用实例源代码

    GridView控件是.NET框架中ASP.NET Web Forms的一个重要组件,常用于展示数据集或数据库中的数据,具有强大的数据绑定和自定义功能。本实例源代码将深入探讨如何使用GridView控件,通过实际操作来理解其核心概念和...

    给ASP.NET中GridView自动添加列排序箭头指示器图片控件源代码

    本知识点将详细介绍如何在GridView中为列添加自定义的排序箭头指示器图片控件,以提供更加直观的用户交互体验。 首先,我们来看标题提到的"自动添加列排序箭头指示器图片控件"。在默认情况下,GridView的列排序功能...

    GridView控件使用练习

    通过本实验的学习与实践,学生将学会如何配置GridView控件,包括数据绑定、样式调整、分页及排序等功能,并了解如何与其他控件(如DropdownList)协同工作以实现更复杂的应用场景。 #### 实验内容详解 **一、简单...

    GridView控件作用大集合

    在这个“GridView控件作用大集合”中,我们将深入探讨其核心功能,包括数据的导入导出、增删查改以及更多的高级特性。 一、数据绑定与显示 GridView控件能够与多种数据源进行绑定,如SQL数据源、ObjectDataSource等...

Global site tag (gtag.js) - Google Analytics