有滚动条、固定Header的ASP.Net DataGrid实现

     有滚动条的ASP.Net DataGrid控件:
  using System;
  using System.Web.UI;
  using System.Web.UI.WebControls;
  using System.ComponentModel;
  using System.Diagnostics;
  using System.IO;
  using System.Web.UI.Design.WebControls;
  using System.Text;
  using System.Drawing;
  [assembly:TagPrefix("Microsoft.Gtec.Dsv", "gtecdsv")]
  namespace Microsoft.Gtec.Dsv
  {
   /// <summary>
   /// Summary description for WebCustomControl1.
   /// </summary>
   [ToolboxData("<{0}:ScrollableFixedHeaderDataGrid runat=server></{0}:ScrollableFixedHeaderDataGrid>")]
   public class ScrollableFixedHeaderDataGrid: System.Web.UI.WebControls.DataGrid
   {
   protected override void Render(HtmlTextWriter output)
   {
   //Use this flag to determine whether the component is in design-time or runtime.
   //The control will be rendered differently in IDE.
   //Don't bother to use DataGridDesigner.GetDesignTimeHtml
   bool designMode = ((Site != null) && (Site.DesignMode));
   //Backing up the properties need to change during the render process
   string tempLeft = Style["LEFT"];
   string tempTop = Style["TOP"];
   Unit tempHeight = Height;
   string tempTableStyle = Style["TABLE-LAYOUT"];
   //Render a "<div>" container with scrollbars.
   output.WriteBeginTag("div");
   output.WriteAttribute("id",ID + "_div");
   output.WriteAttribute("style",
   "HEIGHT: " + Height + ";" +
   //Leave 20px for the vertical scroll bar,
   //assuming the end-user will not set his scroll bar to more than 20px.
   "WIDTH: " + (Width.Value + 20) + "px;" +
   "TOP: " + Style["TOP"] + ";" +
   "LEFT: " + Style["LEFT"] + ";" +
   "POSITION: " + Style["POSITION"] + ";" +
   "OVERFLOW-X: auto;" +
   "Z-INDEX: " + Style["Z-INDEX"] + ";" +
   //Render the scrollbar differently for design-time and runtime.
   "OVERFLOW-Y: " + (designMode?"scroll":"auto")
   );
   output.Write(HtmlTextWriter.TagRightChar);
  
   //The DataGrid is inside the "<div>" element, so place it at (0,0).
   Style["LEFT"] = "0px";
   Style["TOP"] = "0px";
   //Render the DataGrid.
   base.Render(output);
   output.WriteEndTag("div");
   //Restore the values
   Style["LEFT"] = tempLeft;
   Style["TOP"] = tempTop;
   //The following rendering is only necessary under runtime. It has negative impact during design time.
   if (!designMode)
   {
   //Render another copy of the DataGrid with only headers.
   //Render it after the DataGrid with contents,
   //so that it is on the top. Z-INDEX is more complex here.
   //Set Height to 0, so that it will adjust on its own.
   Height = new Unit("0px");
   StringWriter sw = new StringWriter();
   HtmlTextWriter htw = new HtmlTextWriter(sw);
   //This style is important for matching column widths later.
   Style["TABLE-LAYOUT"] = "fixed";
   base.Render(htw);
   StringBuilder sbRenderedTable = sw.GetStringBuilder();
   htw.Close();
   sw.Close();
   Debug.Assert((sbRenderedTable.Length > 0),
   "Rendered HTML string is empty. Check viewstate usage and databinding.");
   string temp = sbRenderedTable.ToString();
   if (sbRenderedTable.Length > 0)
   {
   //AllowPaging at the top?
   if ((AllowPaging) && ((PagerPosition.Top == PagerStyle.Position || (PagerPosition.TopAndBottom == PagerStyle.Position))))
   {
   Trace.WriteLine(temp);
   sbRenderedTable.Replace(ID,ID + "_Pager", 0, (temp.IndexOf(ID) + ID.Length));
   temp = sbRenderedTable.ToString();
   string pager = temp.Substring(0, temp.ToLower().IndexOf(@"</tr>") + 5);
   Trace.WriteLine(pager);
   output.Write(pager);
   output.WriteEndTag("table");
   //Start of pager's <tr>
   int start = temp.ToLower().IndexOf(@"<tr");
   //End of pager's </tr>
   int end = temp.ToLower().IndexOf(@"</tr>") + 5;
   //Remove the <tr> for pager from the string. Prepare to render the headers.
   sbRenderedTable.Remove(start,end-start);
   Trace.WriteLine(sbRenderedTable.ToString());
   sbRenderedTable.Replace(ID + "_Pager",ID + "_Headers", 0, (temp.IndexOf(ID+"_Pager") + (ID+"_Pager").Length));
   temp = sbRenderedTable.ToString();
   string tableHeaders = temp.Substring(0, (temp.ToLower()).IndexOf(@"</tr>") + 5);
   Trace.WriteLine(tableHeaders);
   output.Write(tableHeaders);
   output.WriteEndTag("table");
   string headerID = ID + "_Headers";
   string pagerID = ID + "_Pager";
   string divID = ID + "_div";
   string adjustWidthScript = @"
   <script language=javascript>
   //debugger;
   var headerTableRow = " + headerID + @".rows[0];
   var originalTableRow = " + ID + @".rows[1];"
   //Adjust header row's height.
   + @"
   headerTableRow.height = originalTableRow.offsetHeight;
   " +
   //Adjust pager row's height, width.
   pagerID + @".rows[0].height = " + ID + @".rows[0].offsetHeight;
   " +
   pagerID + @".style.width = " + ID + @".offsetWidth;
   for (var i = 0; i < headerTableRow.cells.length; i++) {
   headerTableRow.cells[i].width = originalTableRow.cells[i].offsetWidth;
   }
   " +
   //Also needs to adjust the width of the "<div>" at client side in addition to servier side,
   //since the Table's actual width can go beyond the width specified at server side under Edit mode.
   //The server side width manipulation is mainly for design-time appearance.
   divID + @".style.width = " + ID + @".offsetWidth + 20 + 'px';
   " +
   //The following script is for flow-layout. We cannot get the position of the control
   //on server side if the the page is with flow-layout.
   headerID + @".style.left = " + divID + @".offsetLeft;
   " +
   headerID + @".style.top = " + divID + @".offsetTop + " + pagerID + @".offsetHeight;
   " +
   headerID + @".style.position = 'absolute';
   " +
   pagerID + @".style.left = " + divID + @".offsetLeft;
   " +
   pagerID + @".style.top = " + divID + @".offsetTop;
   " +
   pagerID + @".style.position = 'absolute';
   </script>";
   Page.RegisterStartupScript("dummyKey" + this.ID, adjustWidthScript);
   //output.Write(adjustWidthScript);
   }
   else
   {
   //Replace the table's ID with a new ID.
   //It is tricky that we must only replace the 1st occurence,
   //since the rest occurences can be used for postback scripts for sorting.
   sbRenderedTable.Replace(ID,ID + "_Headers", 0, (temp.IndexOf(ID) + ID.Length));
   Trace.WriteLine(sbRenderedTable.ToString());
   //We only need the headers, stripping the rest contents.
   temp = sbRenderedTable.ToString();
   string tableHeaders = temp.Substring(0, (temp.ToLower()).IndexOf(@"</tr>") + 5);
   Trace.WriteLine(tableHeaders);
   output.Write(tableHeaders);
   output.WriteEndTag("table");
   //Client side script for matching column widths.
   //Can't find a way to do this on the server side, since the browser can change widths on the client side.
   string adjustWidthScript = @"
   <script language=javascript>
   //debugger;
   var headerTableRow = " + this.ID + @"_Headers.rows[0];
   var originalTableRow = " + this.ID + @".rows[0];
   headerTableRow.height = originalTableRow.offsetHeight;
   for (var i = 0; i < headerTableRow.cells.length; i++) {
   headerTableRow.cells[i].width = originalTableRow.cells[i].offsetWidth;
   }
   " +
   //Also needs to adjust the width of the "<div>" at client side in addition to servier side,
   //since the Table's actual width can go beyond the width specified at server side under Edit mode.
   //The server side width manipulation is mainly for design-time appearance.
   this.ID + "_div" + @".style.width = " + this.ID + @".offsetWidth + 20 + 'px';
   " +
   //The following script is for flow-layout. We cannot get the position of the control
   //on server side if the the page is with flow-layout.
   this.ID + "_Headers" + @".style.left = " + this.ID + @"_div.offsetLeft;
   " +
   this.ID + "_Headers" + @".style.top = " + this.ID + @"_div.offsetTop;
   " +
   this.ID + "_Headers" + @".style.position = 'absolute';
   </script>";
   Page.RegisterStartupScript("dummyKey" + this.ID, adjustWidthScript);
   //output.Write(adjustWidthScript);
   }
   Height = tempHeight;
   Style["TABLE-LAYOUT"] = tempTableStyle;
   }
   }
   }
  
   protected override void OnInit(EventArgs e)
   {
   if (0 == Width.Value) Width = new Unit("400px");
   if (0 == Height.Value) Height = new Unit("200px");
   //Transparent header is not allowed.
   if (HeaderStyle.BackColor.IsEmpty)
   {
   HeaderStyle.BackColor = Color.White;
   }
   //Transparent pager is not allowed.
   if (PagerStyle.BackColor.IsEmpty)
   {
   PagerStyle.BackColor = Color.White;
   }
   base.OnInit (e);
   }
   [Browsable(false)]
   public override bool ShowHeader
   {
   get
   {
   return true;
   }
   set
   {
   if (false == value)
   throw new InvalidOperationException("Use the original DataGrid to set ShowHeaders to false.");
   }
   }
   }
  }

你可能感兴趣的:(datagrid)