Asp.net DataGrid control with Fixed Header and Scrollbar

类别:Asp 点击:0 评论:0 推荐:

接到上面的order, 将DataGrid改写成表头固定, 而要带scroll  bar滚动记录. 看了felix兄的文章

Fixed Header Scrollable DataGrid control
http://blog.joycode.com/felix/articles/32789.aspx

好像有点不太适合自己用. 他将Header截出来, 做成Div, 然后把原来的DataGrid Header盖住, 形成一种假象, 就像表头真的被固定了, 而且两者的位置好像对得不准, 新生成的Header有点左移(不知道是不是我机子的问题).  后来按照我跟上司的设想, 因为DataGrid最终输出的是一个Table, 所以将这个Table拆分为三部份, Header, Items, Pager. 然后在Items外面加一个Div, 用javascript控制Div是否出现Scroll bar.

BTW: 因为DataGrid我们是重新封装过的. 有部份代码只适合此Grid使用, 但万变不离其中.  enjoy it .


  /// <summary>
  /// Author      : Kenneth Lee
  /// Create Date : 2004-11-8
  /// Description : override Render方法, 在网格输出时, 修改网站的样式.
  ///               将整个DataGrid划分为Headers, Items, Pager 三个表格, 利用Div的属性控制是否出现scroll bar.
  ///               并且确保客户端调整控件其它样式时, 其样式保持不变.
   /// </summary>
  /// <param name="writer"></param>
  protected override void Render(HtmlTextWriter writer)
  {
   //确定DataGrid处于何种状态, 是运行时还是设计时
   //Control.Site属性是获取控件当前站点的信息
   bool gridDesignMode = ((Site != null) && (Site.DesignMode));

   //只有运行时输出以下内容
   if (!gridDesignMode)
   {
    
    // 将HTML转换为StringBuilder
    StringWriter sw = new StringWriter();

    HtmlTextWriter htw = new HtmlTextWriter(sw);

    //保证每列的宽度
    Style["TABLE-LAYOUT"] = "fixed";

    // 输出到sw中.
    base.Render(htw);

    StringBuilder sbRenderedTable = sw.GetStringBuilder();

    htw.Close();

    sw.Close();

    string temp = sbRenderedTable.ToString();

    if (sbRenderedTable.Length > 0)
    {
     if (this.HeaderText == string.Empty)
     {
      // 将DataGrid的ID替换为表头ID
      sbRenderedTable.Replace(ID,ID + "_Headers", 0, (temp.IndexOf(ID) + ID.Length));
      
      // 为保持表头和表脚的高度, 将height属性去掉.
      sbRenderedTable.Remove(sbRenderedTable.ToString().ToLower().IndexOf("height:"), this.Height.ToString().Length+8);
      
      temp = sbRenderedTable.ToString();
      
      //找出表头的长度. 以便分拆
      int start = temp.ToLower().IndexOf(@"<");

      int end = temp.ToLower().IndexOf(@">") + 1;

      string strTableStyle = temp.Substring(start,end-start);
      
      
      //因为要将DataGrid划分为三个表格, 所以用一个大的DIV固定它们的宽度.并且保证scroll bar不出现.
      //要确保scroll bar不出, 用overflow-y:hidden就够了
      
      if (this.Height.ToString() == string.Empty || this.Height.ToString() == "100%")
      {
       sbRenderedTable.Insert(0,@"<div id='" + this.ID + "_full' style='Align:center; WIDTH: 100%; overflow-y:hidden'>");
      }
      else
      {
       sbRenderedTable.Insert(0,@"<div id='" + this.ID + "_full' style='Align:center; Width: 100%; overflow-y:hidden;Height:" + this.Height.ToString() + @"'>");
      }
      
      temp = sbRenderedTable.ToString();

      strTableStyle = strTableStyle.Replace(this.ID+"_Headers", ID + "_Items");

      //将表头与内容分拆开. 并为内容加入一个DIV以显示scroll bar
      sbRenderedTable.Insert((temp.ToLower()).IndexOf(@"</tr>") + 5,@"</table>"+ @"<div id='" + this.ID + @"_div' style= 'WIDTH:100%;TOP:;LEFT:;POSITION:;Z-INDEX:;OVERFLOW-X: hidden;OVERFLOW-Y:auto'>
 " + strTableStyle);

      string strTablePager = strTableStyle.Replace(this.ID + "_Items", this.ID + "_Pager");

      int intHeightIndex = strTablePager.ToLower().IndexOf("height:");

      if (intHeightIndex > 0)
      {
       strTablePager = strTablePager.Remove(intHeightIndex, this.Height.ToString().Length+8);
      }

      //将内容与分页拆开.
      sbRenderedTable.Insert(sbRenderedTable.ToString().ToLower().IndexOf(@"<tr style"),@"</table></div>"+strTablePager);

      //使用Javascript将表头的列与内容的列的宽度匹配.
      StringBuilder adjustStyleScript = new StringBuilder();
      adjustStyleScript.Append(@"<script language=javascript>");
      adjustStyleScript.Append(@"var headerTableRow = ");
      adjustStyleScript.Append(this.ID);
      adjustStyleScript.Append(@"_Headers.rows[0];");

      // 判断记录是否为0, 如果为0则无需匹配表头与内容的列宽
      adjustStyleScript.Append(@" if (");
      adjustStyleScript.Append(this.ID);
      adjustStyleScript.Append(@"_Items.rows.length !=0) {");
      adjustStyleScript.Append(@"var originalTableRow = ");
      adjustStyleScript.Append(this.ID);
      adjustStyleScript.Append(@"_Items.rows[0];");
      adjustStyleScript.Append(this.ID);
      adjustStyleScript.Append(@"_Headers.rows[0].width = originalTableRow.offsetWidth;");
      adjustStyleScript.Append(this.ID + @"_Headers.style.width = " + this.ID + @"_full.offsetWidth;");
      adjustStyleScript.Append(this.ID + @"_Pager.style.width = " + this.ID + @"_full.offsetWidth;");
      adjustStyleScript.Append(@"for (var i = 0; i < headerTableRow.cells.length; i++) {");
      adjustStyleScript.Append(@"headerTableRow.cells[i].width = originalTableRow.cells[i].offsetWidth;}");
      adjustStyleScript.Append(@"}");
           
      adjustStyleScript.Append(this.ID);
      adjustStyleScript.Append(@"_Items.style.left = ");
      adjustStyleScript.Append(this.ID);
      adjustStyleScript.Append(@"_div.offsetLeft;");
      
      adjustStyleScript.Append(@"var MinItemHeight = 100;");

      //统计每页一共有多少条记录
      adjustStyleScript.Append(@"var itemsRowsLength = ");
      adjustStyleScript.Append(this.ID);
      adjustStyleScript.Append(@"_Items.rows.length;");

      //计算Items表生成的实际高度.
      adjustStyleScript.Append(@"var itemsTotalHeight = ");
      adjustStyleScript.Append(this.ID);
      adjustStyleScript.Append(@"_Items.rows[0].offsetHeight * itemsRowsLength;");
      
      // 判断整个控件的高度是否比预设的高度要小.
      adjustStyleScript.Append(@"if (");
      adjustStyleScript.Append(this.ID);
      adjustStyleScript.Append(@"_full.offsetHeight < MinItemHeight) {");

      // 判断实际高度是否比减去表头和表脚的高度要小.
         adjustStyleScript.Append(@"if (itemsTotalHeight < MinItemHeight - ");
      adjustStyleScript.Append(this.ID);
      adjustStyleScript.Append(@"_Headers.offsetHeight - ");
      adjustStyleScript.Append(this.ID);
      adjustStyleScript.Append(@"_Pager.offsetHeight) {");
 
      // 将Items外面的Div高度设定与实际生成高度相同.
            adjustStyleScript.Append(this.ID);
      adjustStyleScript.Append(@"_div.style.Height = itemsTotalHeight;");
      adjustStyleScript.Append(this.ID);
      adjustStyleScript.Append(@"_div.style.width = ");
      adjustStyleScript.Append(this.ID);
      adjustStyleScript.Append(@"_full.offsetWidth;");

      // 每行的高度等于实际高度的平均值 
            adjustStyleScript.Append(@"for (var i = 0; i<");
      adjustStyleScript.Append(this.ID);
      adjustStyleScript.Append(@"_Items.rows.length; i++) {");
      adjustStyleScript.Append(this.ID);
      adjustStyleScript.Append(@"_Items.rows[i].height = itemsTotalHeight / itemsRowsLength; }");
      adjustStyleScript.Append(@" }else{");
      adjustStyleScript.Append(this.ID);
      adjustStyleScript.Append(@"_div.style.height = MinItemHeight - ");
      adjustStyleScript.Append(this.ID);
      adjustStyleScript.Append(@"_Headers.offsetHeight - ");
      adjustStyleScript.Append(this.ID);
      adjustStyleScript.Append(@"_Pager.offsetHeight;");
      adjustStyleScript.Append(this.ID);
      adjustStyleScript.Append(@"_div.style.width = ");
      adjustStyleScript.Append(this.ID);
      adjustStyleScript.Append(@"_Items.offsetWidth + 17+ 'px';");
      adjustStyleScript.Append(this.ID);
      adjustStyleScript.Append(@"_full.style.height = ");
      adjustStyleScript.Append(this.ID);
      adjustStyleScript.Append(@"_Headers.offsetHeight + MinItemHeight + ");
      adjustStyleScript.Append(this.ID);
      adjustStyleScript.Append(@"_Pager.offsetHeight;");
      adjustStyleScript.Append(@"}");
      adjustStyleScript.Append(@"} else {");

      // 当整个控件的高度比预设大, 计算去除表头和表脚后的高度.
      adjustStyleScript.Append(@"var itemsHeight = ");
      adjustStyleScript.Append(this.ID);
      adjustStyleScript.Append(@"_full.offsetHeight - ");
      adjustStyleScript.Append(this.ID);
      adjustStyleScript.Append(@"_Headers.offsetHeight - ");
      adjustStyleScript.Append(this.ID);
      adjustStyleScript.Append(@"_Pager.offsetHeight;");
      
      // 判断Items表格的高度是否比去除表头和表脚后的高度要小.  
      adjustStyleScript.Append(@"if (itemsTotalHeight < itemsHeight) {");
      adjustStyleScript.Append(this.ID);
      adjustStyleScript.Append(@"_div.style.width = ");
      adjustStyleScript.Append(this.ID);
      adjustStyleScript.Append(@"_full.offsetWidth;");
      adjustStyleScript.Append(@"for (var i = 0; i<");
      adjustStyleScript.Append(this.ID);
      adjustStyleScript.Append(@"_Items.rows.length; i++) {");
      adjustStyleScript.Append(this.ID);
      adjustStyleScript.Append(@"_Items.rows[i].height = itemsTotalHeight / itemsRowsLength;");
      adjustStyleScript.Append(@" }");
      adjustStyleScript.Append(@" } else {");
      
      // 判断是否需要滚动条
      adjustStyleScript.Append(@"if (");
      adjustStyleScript.Append(this.ID);
      adjustStyleScript.Append(@"_Items.offsetHeight > itemsHeight) {");
      adjustStyleScript.Append(this.ID);
      adjustStyleScript.Append(@"_div.style.width = ");
      adjustStyleScript.Append(this.ID);
      adjustStyleScript.Append(@"_Items.offsetWidth + 17+ 'px';");
      adjustStyleScript.Append(@"} else {");
      adjustStyleScript.Append(this.ID);
      adjustStyleScript.Append(@"_Items.style.height = itemsHeight;");
      adjustStyleScript.Append(@" }");
      adjustStyleScript.Append(this.ID);
      adjustStyleScript.Append(@"_div.style.height = itemsHeight;");
      adjustStyleScript.Append(this.ID);
      adjustStyleScript.Append(@"_div.style.width = ");
      adjustStyleScript.Append(this.ID);
      adjustStyleScript.Append(@"_full.offsetWidth;");
      adjustStyleScript.Append(this.ID);
      adjustStyleScript.Append(@"_full.style.height = itemsHeight + ");
      adjustStyleScript.Append(this.ID);
      adjustStyleScript.Append(@"_Headers.offsetHeight + ");
      adjustStyleScript.Append(this.ID);
      adjustStyleScript.Append(@"_Pager.offsetHeight;");
      adjustStyleScript.Append(@" } } ");

      adjustStyleScript.Append(this.ID);
      adjustStyleScript.Append(@"_div.top = ");
      adjustStyleScript.Append(this.ID);
      adjustStyleScript.Append(@"_Headers.offsetTop + ");
      adjustStyleScript.Append(this.ID);
      adjustStyleScript.Append(@"_Headers.offsetHeight;");

      adjustStyleScript.Append(this.ID);
      adjustStyleScript.Append(@"_Items.style.top = ");
      adjustStyleScript.Append(this.ID);
      adjustStyleScript.Append(@"_div.offsetTop;");

      adjustStyleScript.Append(this.ID);
      adjustStyleScript.Append(@"_Headers.style.position = 'static';");
      adjustStyleScript.Append(@"</script>");

      Page.RegisterStartupScript("dummyKey" + this.ID, adjustStyleScript.ToString());

      sbRenderedTable.Append(@"</div>");
    
      writer.Write(sbRenderedTable.ToString());
     }
     else
     {
      sbRenderedTable.Replace(ID,ID + "_Headers", 0, (temp.IndexOf(ID) + ID.Length));

      //将高度去掉.
      sbRenderedTable.Remove(sbRenderedTable.ToString().ToLower().IndexOf("height:"), this.Height.ToString().Length+8);
      
      // 因为表头存在两行. 所以要分别截取,以统计两行的字符串数.
      int intHeaderLength = 0;
      
      StringBuilder sbNewTable = new StringBuilder(sbRenderedTable.ToString());

      string strBackup;
      string strTableStyle;
      
      temp = sbRenderedTable.ToString();

      int start = temp.ToLower().IndexOf(@"<");

      int end = temp.ToLower().IndexOf(@">") + 1;

      // 将表头格式保存到strBackup和strTableStyle中
      // strBackup的作用是用于统计, <table>, 第一行, 第二行表头的字符串长度.
      // strTableStyle的作用是保存<table>的样式.
      strBackup = strTableStyle = temp.Substring(start,end-start);

      intHeaderLength += strBackup.Length;

      sbNewTable.Remove(start,end-start);

      temp = sbNewTable.ToString();

      start = temp.ToLower().IndexOf(@"<tr");
      
      end = temp.ToLower().IndexOf(@"</tr>") + 5;

      strBackup = temp.Substring(start,end-start);

      intHeaderLength += strBackup.Length;

      sbNewTable.Remove(start,end-start);

      temp = sbNewTable.ToString();

      start = temp.ToLower().IndexOf(@"<tr");
      
      end = temp.ToLower().IndexOf(@"</tr>") + 5;

      strBackup = temp.Substring(start,end-start);

      intHeaderLength += strBackup.Length;
      
      strTableStyle = strTableStyle.Replace(this.ID+"_Headers", ID + "_Items");

      sbRenderedTable.Insert(intHeaderLength+3,@"</table>"+ @"<div id='" + this.ID + @"_div' style= 'WIDTH:100%;TOP:;LEFT:;POSITION:;Z-INDEX:;OVERFLOW-X: hidden;OVERFLOW-Y:auto'>
 " + strTableStyle);

      //因为要将DataGrid划分为三个表格, 所以用一个大的DIV固定它们的宽度.并且保证scroll bar不出现.
      //要确保scroll bar不出, 用overflow-y:hidden就够了
      
      if (this.Height.ToString() == string.Empty || this.Height.ToString() == "100%")
      {
       sbRenderedTable.Insert(0,@"<div id='" + this.ID + "_full' style='Align:center; WIDTH: 100%; overflow-y:hidden'>");
      }
      else
      {
       sbRenderedTable.Insert(0,@"<div id='" + this.ID + "_full' style='Align:center; Width: 100%; overflow-y:hidden;Height:" + this.Height.ToString() + @"'>");
      }

      string strTablePager = strTableStyle.Replace(this.ID+"_Items", this.ID+"_Pager");
      
      sbRenderedTable.Insert(sbRenderedTable.ToString().ToLower().IndexOf(@"<tr style"),@"</table></div>"+strTablePager);

      StringBuilder adjustStyleScript = new StringBuilder();

      adjustStyleScript.Append(@"<script language=javascript>");
      adjustStyleScript.Append(@"var headerTableRow = ");
      adjustStyleScript.Append(this.ID);
      adjustStyleScript.Append(@"_Headers.rows[1];");

      adjustStyleScript.Append(@" if (");
      adjustStyleScript.Append(this.ID);
      adjustStyleScript.Append(@"_Items.rows.length !=0) {");
      adjustStyleScript.Append(@"var originalTableRow = ");
      adjustStyleScript.Append(this.ID);
      adjustStyleScript.Append(@"_Items.rows[0];");
      adjustStyleScript.Append(this.ID);
      adjustStyleScript.Append(@"_Headers.rows[0].width = originalTableRow.offsetWidth;");
      adjustStyleScript.Append(this.ID + @"_Headers.style.width = " + this.ID + @"_full.offsetWidth;");
      adjustStyleScript.Append(this.ID + @"_Pager.style.width = " + this.ID + @"_full.offsetWidth;");
      adjustStyleScript.Append(@"for (var i = 0; i < headerTableRow.cells.length; i++) {");
      adjustStyleScript.Append(@"headerTableRow.cells[i].width = originalTableRow.cells[i].offsetWidth;}");
      adjustStyleScript.Append(@"}");
           
      adjustStyleScript.Append(this.ID);
      adjustStyleScript.Append(@"_Items.style.left = ");
      adjustStyleScript.Append(this.ID);
      adjustStyleScript.Append(@"_div.offsetLeft;");
      
      adjustStyleScript.Append(@"var MinItemHeight = 120;");

      //统计每页一共有多少条记录
      adjustStyleScript.Append(@"var itemsRowsLength = ");
      adjustStyleScript.Append(this.ID);
      adjustStyleScript.Append(@"_Items.rows.length;");

      //计算Items表生成的实际高度.
      adjustStyleScript.Append(@"var itemsTotalHeight = ");
      adjustStyleScript.Append(this.ID);
      adjustStyleScript.Append(@"_Items.rows[0].offsetHeight * itemsRowsLength;");
      
      // 判断整个控件的高度是否比预设的高度要小.
      adjustStyleScript.Append(@"if (");
      adjustStyleScript.Append(this.ID);
      adjustStyleScript.Append(@"_full.offsetHeight < MinItemHeight) {");

      // 判断实际高度是否比减去表头和表脚的高度要小.
      adjustStyleScript.Append(@"if (itemsTotalHeight < MinItemHeight - ");
      adjustStyleScript.Append(this.ID);
      adjustStyleScript.Append(@"_Headers.offsetHeight - ");
      adjustStyleScript.Append(this.ID);
      adjustStyleScript.Append(@"_Pager.offsetHeight) {");
 
      // 将Items外面的Div高度设定与实际生成高度相同.
      adjustStyleScript.Append(this.ID);
      adjustStyleScript.Append(@"_div.style.Height = itemsTotalHeight;");
      adjustStyleScript.Append(this.ID);
      adjustStyleScript.Append(@"_div.style.width = ");
      adjustStyleScript.Append(this.ID);
      adjustStyleScript.Append(@"_full.offsetWidth;");

      // 每行的高度等于实际高度的平均值 
      adjustStyleScript.Append(@"for (var i = 0; i<");
      adjustStyleScript.Append(this.ID);
      adjustStyleScript.Append(@"_Items.rows.length; i++) {");
      adjustStyleScript.Append(this.ID);
      adjustStyleScript.Append(@"_Items.rows[i].height = itemsTotalHeight / itemsRowsLength; }");
      adjustStyleScript.Append(@" }else{");
      adjustStyleScript.Append(this.ID);
      adjustStyleScript.Append(@"_div.style.height = MinItemHeight - ");
      adjustStyleScript.Append(this.ID);
      adjustStyleScript.Append(@"_Headers.offsetHeight - ");
      adjustStyleScript.Append(this.ID);
      adjustStyleScript.Append(@"_Pager.offsetHeight;");
      adjustStyleScript.Append(this.ID);
      adjustStyleScript.Append(@"_div.style.width = ");
      adjustStyleScript.Append(this.ID);
      adjustStyleScript.Append(@"_Items.offsetWidth + 17+ 'px';");
      adjustStyleScript.Append(this.ID);
      adjustStyleScript.Append(@"_full.style.height = ");
      adjustStyleScript.Append(this.ID);
      adjustStyleScript.Append(@"_Headers.offsetHeight + MinItemHeight + ");
      adjustStyleScript.Append(this.ID);
      adjustStyleScript.Append(@"_Pager.offsetHeight;");
      adjustStyleScript.Append(@"}");
      adjustStyleScript.Append(@"} else {");

      // 当整个控件的高度比预设大, 计算去除表头和表脚后的高度.
      adjustStyleScript.Append(@"var itemsHeight = ");
      adjustStyleScript.Append(this.ID);
      adjustStyleScript.Append(@"_full.offsetHeight - ");
      adjustStyleScript.Append(this.ID);
      adjustStyleScript.Append(@"_Headers.offsetHeight - ");
      adjustStyleScript.Append(this.ID);
      adjustStyleScript.Append(@"_Pager.offsetHeight;");
      
      // 判断Items表格的高度是否比去除表头和表脚后的高度要小.  
      adjustStyleScript.Append(@"if (itemsTotalHeight < itemsHeight) {");
      adjustStyleScript.Append(this.ID);
      adjustStyleScript.Append(@"_div.style.width = ");
      adjustStyleScript.Append(this.ID);
      adjustStyleScript.Append(@"_full.offsetWidth;");
      adjustStyleScript.Append(@"for (var i = 0; i<");
      adjustStyleScript.Append(this.ID);
      adjustStyleScript.Append(@"_Items.rows.length; i++) {");
      adjustStyleScript.Append(this.ID);
      adjustStyleScript.Append(@"_Items.rows[i].height = itemsTotalHeight / itemsRowsLength;");
      adjustStyleScript.Append(@" }");
      adjustStyleScript.Append(@" } else {");
      
      // 判断是否需要滚动条
      adjustStyleScript.Append(@"if (");
      adjustStyleScript.Append(this.ID);
      adjustStyleScript.Append(@"_Items.offsetHeight > itemsHeight) {");
      adjustStyleScript.Append(this.ID);
      adjustStyleScript.Append(@"_div.style.width = ");
      adjustStyleScript.Append(this.ID);
      adjustStyleScript.Append(@"_Items.offsetWidth + 17+ 'px';");
      adjustStyleScript.Append(@"} else {");
      adjustStyleScript.Append(this.ID);
      adjustStyleScript.Append(@"_Items.style.height = itemsHeight;");
      adjustStyleScript.Append(@" }");
      adjustStyleScript.Append(this.ID);
      adjustStyleScript.Append(@"_div.style.height = itemsHeight;");
      adjustStyleScript.Append(this.ID);
      adjustStyleScript.Append(@"_div.style.width = ");
      adjustStyleScript.Append(this.ID);
      adjustStyleScript.Append(@"_full.offsetWidth;");
      adjustStyleScript.Append(this.ID);
      adjustStyleScript.Append(@"_full.style.height = itemsHeight + ");
      adjustStyleScript.Append(this.ID);
      adjustStyleScript.Append(@"_Headers.offsetHeight + ");
      adjustStyleScript.Append(this.ID);
      adjustStyleScript.Append(@"_Pager.offsetHeight;");
      adjustStyleScript.Append(@" } } ");

      adjustStyleScript.Append(this.ID);
      adjustStyleScript.Append(@"_div.top = ");
      adjustStyleScript.Append(this.ID);
      adjustStyleScript.Append(@"_Headers.offsetTop + ");
      adjustStyleScript.Append(this.ID);
      adjustStyleScript.Append(@"_Headers.offsetHeight;");

      adjustStyleScript.Append(this.ID);
      adjustStyleScript.Append(@"_Items.style.top = ");
      adjustStyleScript.Append(this.ID);
      adjustStyleScript.Append(@"_div.offsetTop;");

      adjustStyleScript.Append(this.ID);
      adjustStyleScript.Append(@"_Headers.style.position = 'static';");
      adjustStyleScript.Append(@"</script>");

      Page.RegisterStartupScript("dummyKey" + this.ID, adjustStyleScript.ToString());

      sbRenderedTable.Append(@"</div>");
      
      writer.Write(sbRenderedTable.ToString());
     }
    }    
   }
   else
   {
    // 不会执行此句, 只有在设计视图中出现DataGrid
    base.Render(writer);
   }
  }

本文地址:http://com.8s8s.com/it/it7997.htm