ASP.NET GridView 排序指示器组件






4.43/5 (12投票s)
本文介绍了一个组件,该组件可在 GridView 的列标题中显示数据排序所依据的排序指示器。
引言
本文介绍了一个用于在 GridView
列中添加排序指示器图像的组件。
互联网上有很多关于如何为 GridView
添加某种排序指示器的网站,但它们都是针对单个 GridView
的。我们的应用程序有相当多的 GridView
需要此功能,因此我决定创建一个组件是正确的方法。组件的优点在于我可以只编写一次行为,而无需为每个单独的 GridView
反复编写。
本文的其余部分将展示如何使用 GridViewSortExtender
(组件名称)以及它内部的工作原理。
直接使用
要使用 GridViewSortExtender
,只需将其与要扩展的 GridView
放在同一页面上即可。
然后,在属性窗格中设置图像的属性,并指定应扩展哪个 GridView
。
就是这样!运行应用程序。它看起来会像这样。
内部原理
GirdViewSortExtender
是一个相当简单的组件,但其中仍有一些有趣之处,我将在本节中进行讨论。
如何将指示器添加到排序列
我使用 GridViewSortExtender
的 OnPreRender
方法来修改已扩展的 GridView
。这在我的项目中有效,因为我通常不再在页面本身的 OnPreRender
方法中修改页面内容。注意:页面上的 OnPreRender
在包含组件的 OnPreRender
方法之后被调用。
注意:图像始终被添加,否则在不绑定 GridView
的回发中将丢失(有关更多信息,请参见下方的消息部分)。
public class GridViewSortExtender : Control
{
/// ... other code ...
/// <summary>
/// Adds an event handler to the DataBound event of the extended GridView.
/// </summary>
/// <param name="e"></param>
protected override void OnPreRender(EventArgs e)
{
base.OnInit(e);
GridView extendee =
this.NamingContainer.FindControl(this.ExtendeeID) as GridView;
if (extendee != null &&
extendee.AllowSorting &&
extendee.HeaderRow != null &&
!String.IsNullOrEmpty(extendee.SortExpression))
{
int field = GetSortField(extendee);
if (field >= 0)
{
Image img = new Image();
img.ImageUrl =
extendee.SortDirection == SortDirection.Ascending ?
this.AscendingImageUrl : this.DescendingImageUrl;
img.ImageAlign = ImageAlign.TextTop;
extendee.HeaderRow.Cells[field].Controls.Add(img);
}
}
}
/// <summary>
/// Returns the index of the sort-column.
/// </summary>
/// <param name="extendee"></param>
/// <returns></returns>
private int GetSortField(GridView extendee)
{
int i = 0;
foreach (DataControlField field in extendee.Columns)
{
if (field.SortExpression == extendee.SortExpression)
{
return i;
}
i++;
}
return -1;
}
}
第一件事是获取已扩展的 GridView
。这可以通过调用 GridViewSortExtender
的 NamingContainer
上的 FindControl
方法来实现。NamingContainer
是定义 GridViewSortExtender
的容器。因此,GridViewSortExtender
必须与它所扩展的 GridView
位于同一容器中。
如果找到了相应的 GridView
,则会检查该 GridView
是否允许排序并且具有标题行——只有这样,添加排序指示器才是有意义的。
然后,根据已扩展 GridView
的 SortDirection
,实例化一个图像。
棘手的部分是如何找到添加图像的正确列。我遍历已扩展 GridView
的所有列,并将其 SortExpression
与 GridView
的 SortExpression
进行比较——如果相同,则找到了正确的列。
最后,我将图像添加到该列的标题单元格中。
使用 SortExpression
的一个缺点是 GridViewSortExtender
仅适用于 BoundField
列。当您拥有具有动态生成列的 GridView
时,这尤其成问题。
旁注:通常,我会重写事件调用方方法(如 OnPreRender
)而不是注册事件(如 PreRender
),因为我不喜欢实例注册自身的事件。我认为这是糟糕的面向对象设计 :-)
如何使其支持设计器
我在我的应用程序中经常使用此组件,因此我希望有一个在设计器中具有良好行为的组件。
引用图像
GridViewSortExtender
有两个图像引用。我使用 Editor
属性在设计器中获得一个漂亮的选对话框。图像的 URL 然后存储在 ViewState
中。
/// <summary>
/// Image that is displayed when SortDirection is ascending.
/// </summary>
[DefaultValue("")]
[Editor(typeof(ImageUrlEditor), typeof(UITypeEditor))]
[Description("Image that is displayed when SortDirection is ascending.")]
public string AscendingImageUrl
{
get { return this.ViewState["AscendingImageUrl"] != null ?
(string)this.ViewState["AscendingImageUrl"] : ""; }
set { this.ViewState["AscendingImageUrl"] = value; }
}
引用 GridView
为了获得类似的可扩展 GridView
选择行为,我为 ExtendeeID
属性选择了 IDReferenceProperty
。不幸的是,结果不稳定:有时设计器会在属性列表中的选择列表中提供页面上的所有 GridView
,有时则不会。因此,我添加了 TypeConverter
属性和一个自定义 TypeConverter
(GridViewIDConverter
)。现在,设计器可以可靠地提供页面上所有 DataGrid
的选择。
/// <summary>
/// The GridView that is extended.
/// </summary>
[DefaultValue("")]
[IDReferenceProperty(typeof(GridView))]
[TypeConverter(typeof(GridViewIDConverter))]
[Description("The GridView that is extended.")]
public string ExtendeeID
{
get { return this.ViewState["Extendee"] != null ?
(string)this.ViewState["Extendee"] : ""; }
set { this.ViewState["Extendee"] = value; }
}
GridViewIDConverter
继承自通用的 ControlIDConverter
,它为我们做了大部分工作。我们仍然需要做的就是定义在设计器提供给程序员的列表中应可见哪些控件。在这种情况下,我只需定义该控件必须是 GridView
。
public class GridViewIDConverter : ControlIDConverter
{
// Methods
protected override bool FilterControl(Control control)
{
return control is GridView;
}
}
在设计器中显示 GirdViewSortExtender
我添加了一个自定义控件设计器,以便在设计模式下获得组件的美观外观。Designer
属性指示我想将 GridViewSortExtenderDesigner
用作我的组件的设计器。GridViewSortExtenderDesigner
继承自 CodeDesigner
,并重写了 GetDesignTimeHtml
方法以返回用于在设计模式下显示组件的 HTML。
注意:您可以在上面的图片中看到它的外观。
[Designer(typeof(GridViewSortExtenderDesigner))]
public class GridViewSortExtender : Control
{
... some code ...
}
/// <summary>
/// Designer for <see cref="GridViewSortExtender"/>.
/// </summary>
public class GridViewSortExtenderDesigner : ControlDesigner
{
public override string GetDesignTimeHtml()
{
return
"<div style=\"background-color: #C8C8C8; " +
"border: groove 2 Gray;\"><b>GridViewSortExtender</b> - " +
this.Component.Site.Name + "</div>";
}
}
可能的扩展
- 当列未排序时添加分隔符图像(防止列宽更改)。
结论
GridViewSortExtenderDesigner
是一个简单的组件,用于向 GridView
添加排序指示器,并且具有良好的设计时行为,可简化在具有多个可排序 GridView
的项目中的使用。
代码来源
示例代码摘自我为 bbv Software Services AG 编写的 Web 应用程序。
感谢允许我撰写此文。
历史
- 2007-07-23 - 初始版本。
- 2007-08-06 - 使用
GridView
上的DataBound
事件。感谢 Michael Tucker 的建议。 - 2007-08-07 - 改回
PreRender
方法,因为否则在不绑定GridView
的回发中会丢失排序指示器。感谢 Kelly Herald 的反馈。