客户要一个有滚动条的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 description for WebCustomControl1.
///
[ToolboxData("")]
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 "" 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 "" 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(@"") + 5);
Trace.WriteLine(pager);
output.Write(pager);
output.WriteEndTag("table");
//Start of pager's
int start = temp.ToLower().IndexOf(@"
//End of pager's
int end = temp.ToLower().IndexOf(@"") + 5;
//Remove the 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(@"") + 5);
Trace.WriteLine(tableHeaders);
output.Write(tableHeaders);
output.WriteEndTag("table");
string headerID = ID + "_Headers";
string pagerID = ID + "_Pager";
string divID = ID + "_div";
string adjustWidthScript = @"