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

使用 JavaScript 和 CSS 冻结 ASP.NET GridView 标题

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.55/5 (13投票s)

2008年10月31日

CPOL

2分钟阅读

viewsIcon

198227

downloadIcon

4385

使用 JavaScript 和 CSS 冻结 ASP.NET GridView 标题。

FreezeGridViewHeader

引言

如今,对于 Web 开发人员来说,冻结 ASP.NET GridView 标题是一个常见的需求。出于可用性的考虑,对于像 DataGridGridView 或原始 HTML 表格等数据查看控件,冻结或固定标题是必不可少的。您可能已经注意到,在 Excel 中,您可以冻结电子表格的标题单元格。当您向下滚动时,标题始终可见,使您的表格更易于阅读。通常需要在 GridView 控件中实现相同的效果,尤其是在一次显示许多记录时。 在本文中,我将解释一种可以轻松实现此效果的技术。

概念讨论

我们都知道,在执行服务器端代码后,原始 HTML 会返回到浏览器,浏览器只是显示 HTML。显然,GridView 需要转换为 HTML 表格。因此,我们需要对返回的表格进行一些自定义才能达到我们的目标。以下是一些执行该自定义的步骤:

  1. 移除通常表示标题的表格行,并将其分配给新创建的“<THEAD>”标签。
  2. 通过限制表格的高度并添加“overflow: auto”属性到“<TBODY>”和“<DIV>”内部,使表格/网格的其余行可滚动。“<DIV>”只是网格上方的包装器,有助于表示可滚动的选项。
  3. 现在,使用适用于浏览器的技术(因为不同的浏览器在这种情况下表现不同)固定/冻结“<THEAD>”。

现在,无论您滚动网格行,标题始终保持在顶部行。

Using the Code

完整的示例代码如下所示。您还可以从上面的链接下载示例项目。

<%@ Page Language="C#" AutoEventWireup="true" 
         CodeFile="Default.aspx.cs" Inherits="_Default" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<style type="text/css">
    .WrapperDiv 
    {
        width:560px;height:290px;border: 1px solid black;
    }        
    .WrapperDiv TH 
    {
        /* Needed for IE */
         position: relative;
    }
    .WrapperDiv TR 
    {
        /* Needed for IE */
        height:0px;
    }
    .ScrollContent 
    {
        /* Needed for Opera */
        display: block;
        overflow: auto;
        width: 100%;
        height: 250px;
    }
    .FixedHeader
    {
        /* Needed for opera */
        display: block;
    }
    
</style>

<script runat="server">
  ICollection CreateDataSource( )
  {
    System.Data.DataTable dt = new System.Data.DataTable();
    System.Data.DataRow dr;
    dt.Columns.Add(new System.Data.DataColumn("Product Id", typeof(System.String)));
    dt.Columns.Add(new System.Data.DataColumn("Product Name", typeof(System.String)));
    dt.Columns.Add(new System.Data.DataColumn("Product Price", typeof(System.Decimal)));
    dt.Columns.Add(new System.Data.DataColumn("Manufacture Time", typeof(System.String)));
    dt.Columns.Add(new System.Data.DataColumn("Expired Time", typeof(System.String)));
    
    for (int i = 1; i <= 50; i++)
    {
      System.Random rd = new System.Random(Environment.TickCount * i); ;
      dr = dt.NewRow();
      dr[0] = i.ToString();
      dr[1] = "Sample Product" + i.ToString();
      dr[2] = System.Math.Round(rd.NextDouble() * 100, 2);
      dr[3] = "September/2008";
      dr[4] = "September/2012";
      dt.Rows.Add(dr);
    }
    System.Data.DataView dv = new System.Data.DataView(dt);
    return dv;
  }

  protected void Page_Load( object sender, EventArgs e )
  {
    if (!IsPostBack)
    {
      GridView1.DataSource = CreateDataSource();
      GridView1.DataBind();
    }
  }
  
</script>

<script type="text/ecmascript">

    var headerHeight = 8;

    /// <summary>
    ///  Responsible for call appropriate function according to browser
    ///  for Browser Compatibility
    /// </summary>
    function onLoad()
    {
        if(navigator.appName == "Opera")
        {
            freezeGridViewHeaderForOpera('GridView1');
        }
        else
        {
            freezeGridViewHeaderForIEAndFF('GridView1','WrapperDiv');
        }
    }
    
    /// <summary>
    ///  Used to create a fixed GridView header and allow scrolling
    ///  for IE and FF (Tested in IE-7 and FF-3.0.3)
    /// </summary>
    /// <param name="gridViewId" type="String">
    ///   Client-side ID of the GridView control
    /// </param>
    /// <param name="wrapperDivCssClass" type="String">
    ///   CSS class to be applied to the GridView's wrapper div element.
    /// </param>
    function freezeGridViewHeaderForIEAndFF(gridViewId,wrapperDivCssClass) 
    {
        var grid = document.getElementById(gridViewId);
        if (grid != 'undefined')
        {
            grid.style.visibility = 'hidden';
            
            var div = null;
            if (grid.parentNode != 'undefined') 
            {
                //Find wrapper div output by GridView
                div = grid.parentNode;
                if (div.tagName == "DIV")
                {
                    div.className = wrapperDivCssClass;  
                    div.style.overflow = "auto";             
                }
            }  
                       
            var grid = prepareFixedHeader(grid);
            var tbody = grid.getElementsByTagName('TBODY')[0];
            
            //Needed for Firefox
            tbody.style.height = (div.offsetHeight -  headerHeight) + 'px';

            tbody.style.overflowX = "hidden";
            tbody.overflow = 'auto';
            tbody.overflowX = 'hidden';
             
            grid.style.visibility = 'visible';
        }
    }
    
    /// <summary>
    ///  Used to create a fixed GridView header and allow scrolling
    ///  for Opera (Tested in Opera-9.2)
    /// </summary>
    /// <param name="gridViewId" type="String">
    ///   Client-side ID of the GridView control
    /// </param>
    function freezeGridViewHeaderForOpera(gridViewId)
    {
        var grid = document.getElementById(gridViewId);
        if (grid != 'undefined')
        {
            grid = prepareFixedHeader(grid);

            var headers = grid.getElementsByTagName('THEAD')[0];
            headers.className = "FixedHeader";
            
            var tbody = grid.getElementsByTagName('TBODY')[0];
            tbody.className = "ScrollContent";
            var cells = tbody.childNodes[0];

            for(var i = 0; i < cells.childNodes.length;i++)
            {
                var tableCell = cells.childNodes[i];
                var tableCellWidth = getStyle(tableCell,'width')
                var headerCell = headers.childNodes[0].childNodes[i];

                var headerCellWidth = getStyle(headerCell,'width');

                if(widthPxToInt(tableCellWidth) > widthPxToInt(headerCellWidth))
                {
                    headerCell.style.width=(widthPxToInt(tableCellWidth) - 10) + "px";
                }
                else
                {
                    tableCell.style.width=(widthPxToInt(headerCellWidth) - 10) + "px";
                }
            }
        }
    }
    
    /// <summary>
    ///  Used to prepare a fixed GridView header
    /// </summary>
    /// <param name="grid" type="GridView">
    ///   The Reference Of GridView control
    /// </param>
    function prepareFixedHeader(grid)
    {
        //Find DOM TBODY element and  and 
        var tags = grid.getElementsByTagName('TBODY');
        if (tags != 'undefined')
        {
            var tbody = tags[0];
            
            var trs = tbody.getElementsByTagName('TR');

            if (trs != 'undefined') 
            {
                headerHeight += trs[0].offsetHeight;
                
                //Remove first TR tag from it        
                var headTR = tbody.removeChild(trs[0]);
                
                //create a new element called THEAD
                var head = document.createElement('THEAD');
                head.appendChild(headTR);
                
                //add to a THEAD element instead of TR so CSS styles
                //can be applied properly in both IE and FireFox
                grid.insertBefore(head, grid.firstChild);
            }
       }
       
       return grid;
    }
    
    function getStyle(oElm, strCssRule)
    {
        var strValue = "";
        if(document.defaultView && document.defaultView.getComputedStyle){
           strValue = document.defaultView.getComputedStyle(oElm, 
                               "").getPropertyValue(strCssRule);
        }
        else if(oElm.currentStyle){
            strCssRule = strCssRule.replace(/\-(\w)/g, function (strMatch, p1){
                return p1.toUpperCase();
            });
            strValue = oElm.currentStyle[strCssRule];
        }
        return strValue;
    }
    
    /// <summary>
    ///  Used to convert from Pxel to Integer
    /// </summary>
    /// <param name="width" type="String">
    ///  Width of any thing like GridHeader,GridCell
    /// </param>    
    function widthPxToInt(width)
    {
        width = width.substr(0,width.length-2);
        return new Number(width);
    }
    
    
</script>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title>Untitled Page</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:GridView ID="GridView1" runat="server" 
              Font-Size="12px" BackColor="#FFFFFF"
              GridLines="Both" CellPadding="4" Width="560px">
          <HeaderStyle BackColor="#EDEDED" Height="26px" />
        </asp:GridView>
    </div>
    </form>
</body>
</html>

<script type="text/ecmascript">   
    window.onload = onLoad();
</script>

浏览器兼容性

由于我使用了 JavaScript 和 CSS 来解决此问题,因此毫无疑问会引发“此解决方案是否与所有浏览器兼容?”的问题。如果您在 Google 上搜索,您会找到许多针对此问题的解决方案。但我尚未找到支持所有浏览器的客户端解决方案。大多数解决方案支持 Firefox 和 IE。但很少支持 Opera。

我在 FireFox-3.0.3、IE-7 和 Opera-9.2 中测试了提供的解决方案,并获得了成功的结果。

© . All rights reserved.