您的位置:首页 > 编程语言 > ASP

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

2004-11-25 09:08 585 查看
客户要一个有滚动条的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.");
}
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: