客戶要一個有滾動條的ASP.Net DataGrid控件,隻好寫了:
");>
using
System;
System.Web.UI;
System.Web.UI.WebControls;
System.ComponentModel;
System.Diagnostics;
System.IO;
System.Web.UI.Design.WebControls;
System.Text;
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
];
tempTop
TOP
Unit tempHeight
Height;
tempTableStyle
TABLE-LAYOUT
Render a "<div>" container with scrollbars.
output.WriteBeginTag(
div
);
output.WriteAttribute(
id
,ID
+
_div
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:
]
LEFT:
POSITION:
POSITION
OVERFLOW-X: auto;
Z-INDEX:
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[
0px
Render the DataGrid.
base
.Render(output);
output.WriteEndTag(
Restore the values
tempLeft;
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(
StringWriter sw
StringWriter();
HtmlTextWriter htw
HtmlTextWriter(sw);
This style is important for matching column widths later.
Style[
fixed
.Render(htw);
StringBuilder sbRenderedTable
sw.GetStringBuilder();
htw.Close();
sw.Close();
Debug.Assert((sbRenderedTable.Length
>
),
Rendered HTML string is empty. Check viewstate usage and databinding.
temp
sbRenderedTable.ToString();
(sbRenderedTable.Length
{
AllowPaging at the top?
((AllowPaging)
((PagerPosition.Top
==
PagerStyle.Position
||
(PagerPosition.TopAndBottom
PagerStyle.Position))))
{
Trace.WriteLine(temp);
sbRenderedTable.Replace(ID,ID
_Pager
, (temp.IndexOf(ID)
ID.Length));
temp
pager
temp.Substring(
, 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>
end
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
_Headers
, (temp.IndexOf(ID
(ID
).Length));
tableHeaders
, (temp.ToLower()).IndexOf(
Trace.WriteLine(tableHeaders);
output.Write(tableHeaders);
headerID
ID
pagerID
divID
adjustWidthScript
<script language=javascript>
//debugger;
var headerTableRow =
.rows[0];
var originalTableRow =
.rows[1];
Adjust header row's height.
headerTableRow.height = originalTableRow.offsetHeight;
Adjust pager row's height, width.
pagerID
.rows[0].height =
.rows[0].offsetHeight;
.style.width =
.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
.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 =
.offsetLeft;
.style.top =
.offsetTop +
.offsetHeight;
.style.position = 'absolute';
.offsetTop;
</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.
We only need the headers, stripping the rest contents.
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.
.ID
_Headers.rows[0];
_div.offsetLeft;
_div.offsetTop;
Height
tempHeight;
Style[
tempTableStyle;
}
}
}
OnInit(EventArgs e)
Width.Value) Width
400px
Height.Value) Height
200px
Transparent header is not allowed.
(HeaderStyle.BackColor.IsEmpty)
HeaderStyle.BackColor
Color.White;
Transparent pager is not allowed.
(PagerStyle.BackColor.IsEmpty)
PagerStyle.BackColor
.OnInit (e);
[Browsable(
false
ShowHeader
get
return
true
set
value)
throw
InvalidOperationException(
Use the original DataGrid to set ShowHeaders to false.
}
}