65.9K
CodeProject 正在变化。 阅读更多。
Home

扩展 ASP.NET 控件:可滚动 GridView

starIconstarIconstarIconstarIconstarIcon

5.00/5 (18投票s)

2013 年 4 月 5 日

CPOL

5分钟阅读

viewsIcon

87802

downloadIcon

3112

扩展标准的 ASP.NET GridView 控件以在网格中添加垂直滚动条

Scrollbar in the GridView

引言

尽管 ASP.NET 提供了大量可自定义的 Web 控件,但在某些情况下,您可能希望扩展 Web 控件的功能和行为。幸运的是,ASP.NET 控件有许多扩展点:

  1. 可自定义属性
  2. 样式和 CSS 类
  3. 模板化
  4. 重写

虽然前三个选项可以在运行时配置,但第四个选项需要一些编码。当您希望更改控件的行为或布局时,需要进行重写。在这种情况下,通常会为 Web 控件创建一个子类,并在其中实现重写的方法。

本文提供了一个示例,用于扩展标准的 ASP.NET GridView 控件,使其可以选择显示滚动条(也称为带固定页眉的可滚动表),而不是使用标准的“分页”,从而允许一次显示所有列表项。此解决方案已在 Internet Explorer、Firefox 和 Chrome 中进行过测试。

背景

Web 标准规定在浏览大型列表时要具有“分页”功能。其思想是大型列表需要“很长时间”才能下载,因此在使用分页时,用户只需下载包含少量行的单个页面。

标准的 ASP.NET GridView 默认支持分页。奇怪的是,GridView 在优化加载时间方面并没有多大作用,因为默认情况下绑定到 gridview 的列表存储在 ViewState 中,因此仍然会生成“大型”页面,导致下载时间更长。
因此,您也可以选择忽略分页,而一次显示整个列表。这样做的好处是,每次用户在网格中选择不同页面时,都不需要重新加载页面。

显然,列表可能会变得太大而无法容纳在单个网页中,因此使用滚动条将是一个足够好的解决方案。这在桌面应用程序中很常见。但是我发现,向 GridView 添加滚动条并非易事:目标是只让列表项可滚动,同时保持 gridview 页眉固定。

我曾寻找解决此问题的方法,但一些提出的解决方案仅兼容某些浏览器(例如,基于 CSS 的),其他一些则相当复杂或仅在特定情况下有效。据我所知,对于 GridView 控件,没有可用的标准解决方案。本文提出的解决方案与各种常用浏览器兼容,并且可以轻松地集成到任何 ASP.NET 解决方案中。此外,最终渲染的 HTML 尽可能紧凑。

解决方案

解决方案的方法并不新颖,例如,请参阅此处的一个示例:此处。基本上,页眉行显示在页眉 DIV 中的一个表中,而正文行显示在单独的可滚动正文 DIV 元素中。此方法会带来以下需要解决的问题:

从 GridView 中提取页眉行并在单独的 DIV 和 TABLE 中渲染它

这需要一些调整才能使其正常工作。它需要重写 GridView 控件的默认 RenderChildren 方法。RenderChildren 方法负责生成写入响应对象的输出。我重排并插入了我自己的某些 HTML 元素,而不是生成默认的 GridView html 元素。

基本上,我使用的是以下步骤:

  1. 创建一个新的页眉 DIV html 元素。为其分配一个特殊的 css-class,以便 JQuery 可以访问它。
        System.Web.UI.HtmlControls.HtmlGenericControl divhead = 
                         new System.Web.UI.HtmlControls.HtmlGenericControl("DIV");
        divhead.Attributes["class"] = "GridViewHeaderContainer"; // Assign a css-style 
                                                                 // accessible by jquery
        divhead.Style.Add("overflow", "hidden");                 // Make sure the inner table 
                                                                 // will not overflow
        if (this.Width != Unit.Empty)
            divhead.Style.Add("width", this.Width.ToString());   // Assign new width, 
                                                                 // overrule stylesheet. 
                                                                 // Use width defined 
                                                                 // in the control
  2. 创建一个新的 Table 对象并将其插入到页眉 DIV 中。确保应用了正确的样式。
        Table tablehead = new Table();
        tablehead.ApplyStyle(this.HeaderStyle);
        tablehead.Style.Add("width", "100%");
        tablehead.ID = ctrl.UniqueID + "$Header";            
        divhead.Controls.Add(tablehead); 
  3. 选择 GridView 中的页眉行并将其插入到新创建的表中(请注意,这将从原始表中删除该行!)。
        WebControl ctrl = (WebControl)this.Controls[0]; // Reference the table
        Control ctrlrow = ctrl.Controls[0];             // Reference the first row: 
                                                        // table->row[0]
        tablehead.Controls.Add(ctrlrow);                // This will automatically 
                                                        // bind the row to the new 
                                                        // parent control (and remove 
                                                        // itself from the previous container)
  4. 渲染页眉 DIV(这将自动渲染其子元素)。
         divhead.RenderControl(writer);                 // will render the DIV 
                                                        // including the table 
                                                        // containing only the header.
  5. 创建正文 DIV
         System.Web.UI.HtmlControls.HtmlGenericControl divbody = 
                      new System.Web.UI.HtmlControls.HtmlGenericControl("DIV");
  6. 设置 DIVstyle 属性,并确保它是可滚动的。
            divbody.Attributes["class"] = "GridViewBodyContainer";   // style is hardcoded 
                                                                     // for jquery
            if (this.Width != Unit.Empty)
                divbody.Style.Add("width", this.Width.ToString());   // Assign new width.
    
            if (this.Height != Unit.Empty)                           // Note: if no height
                                                                     // is set, 
                                                                     // scrollbars will not be 
                                                                     // visible since all rows 
                                                                     // will be displayed then
                divbody.Style.Add("height", this.Height.ToString()); // Assign new height.
    
            divbody.Style.Add("margin", "0px");
            divbody.Style.Add("overflow", "hidden");
            divbody.Style.Add("overflow-y", "auto");
  7. 将页眉行插入到原始表中的位置 0(顶部)。
             ctrl.Controls.AddAt(0, ctrlrow); // This will automatically bind the row 
                                              // to the parent table (and remove itself 
                                              // from previous container)
  8. GridView 表插入到正文 DIV 中并渲染正文 DIV
            divbody.Controls.AddAt(0, ctrl);  // Bind the table to the body DIV 
                                              // (and remove itself from previous container)
            divbody.RenderControl(writer);    // will render the DIV and the included table
  9. 将表插入到 GridView 中。这是一个关键步骤,因为它会将 GridView 恢复到其原始状态。
            this.Controls.AddAt(0, ctrl);     // Restore to previous container, 
                                              // this way the control will not break
  10. 渲染 gridview 中包含的任何其他控件(例如页脚)
            for (int i = 1; i < this.Controls.Count; i++)
            {
                ctrl = (WebControl)this.Controls[i];
                ctrl.RenderControl(writer);
            }

使页眉行的列与正文表中的列对齐

为了确保两个表的列对齐,会使用一些 JavaScript/JQuery。该脚本包含一个名为 UpdateGrid() 的函数,该函数在 gridview 完全渲染*之后*被调用。此时,列宽度已知,并在运行时重新对齐。它将根据 css-class 查找 DIV,并遍历所有行和列以确定宽度。然后,它将显式设置每个表单元格的宽度。

完成后,它将使正文中的第一行(即原始页眉行)不可见。由于这是在渲染之后完成的,因此有时可能会短暂显示两个页眉。这是此方法唯一的缺点。

在 UpdatePanel 中使用 Grid

为了支持 GridUpdatePanel 中的更新,需要额外的 JavaScript 代码来确保 Grid 在每次(部分)回发到服务器后都能正确刷新和重新对齐。每次 UpdatePanel 更新其内容时,都必须调用 UpdateGrid() JavaScript 函数。为此,必须在 ScriptManager 声明之后立即在网页中声明以下处理程序:

    <asp:ScriptManager ID="ScriptManager1" runat="server" />
    <script type="text/javascript">
        Sys.Application.add_load(function () { UpdateGrid(); });
    </script>

这个巧妙的小技巧将使网格与 UpdatePanel 同步。

Using the Code

提供的解决方案包含 2 个文件:

  • ScrollableGridView.cs
  • ScrollableGridView.js

您可以将这些文件添加到自己的 ASP.NET 解决方案中,或者直接从 ControlExtensions 组件中使用 ScrollableGridView。您需要从 Web 项目向该组件添加引用。

将以下几行添加到您的网页中:

<%@ Register TagPrefix="ce" Namespace="Grids" Assembly="ControlExtensions" %>

<!-- add the following js scripts -->;
<script type="text/javascript" src="Scripts/jquery-1.4.1.min.js"></script>
<script type="text/javascript" src="Scripts/ScrollableGridView.js"></script>

...

<!-- insert the scrollable gridview control on the page at the desired position 
make sure to set the Height property of the control to make sure scrollbars are displayed-->
<ce:ScrollableGridView id="ScrollableGridView1" runat="server" height="360px" width="100%">
    <HeaderStyle BackColor="Orange" />
</ce:ScrollableGridView>

...

这足以支持 GridView 中的滚动。在此处包含的示例应用程序中,为了填充列表,会生成一些随机行。这仅出于测试目的而在页面的代码隐藏中完成。

此外,还添加了一个示例网页,用于演示如何在 UpdatePanel 控件的组合中使用此网格。

关注点

我很高兴地发现,通过重写 RenderChildren 方法,GridView 可以以非常不同的方式进行渲染。这使得现有 ASP.NET 控件易于重用和扩展。

历史

  • 2013 年 4 月 5 日:发布 1.0 版本
  • 2013 年 4 月 17 日:发布 1.1 版本
© . All rights reserved.