冻结窗格 DataGrid






4.68/5 (59投票s)
创建一个 DataGrid,能够锁定标题行和第一列。
引言
在最近的一个项目中,我被要求使 DataGrid
的行为类似于 Excel 的冻结窗格。没错,就是冻结标题行和 DataGrid
的左侧列。在花费数小时搜索已经完成并发布代码的人之后,我放弃并尝试自己找出解决方案。上面的项目源代码提供了三个 ASPX 文件。一个用于从客户端锁定列,一个用于从服务器端锁定列,还有一个用于从服务器端锁定列,然后从客户端解锁/锁定列。
背景
这个计划实际上相当简单。在网上搜索解决方案时,我发现一篇关于如何从 HTML 表格创建冻结窗格的精彩文章。该解决方案基于 CSS,仅适用于 Internet Explorer,但在其他浏览器中表现良好。我想感谢 Brett Merkey 提供的这个解决方案。他的“锁定或冻结带有非滚动标题的列”为我提供了灵感,可以在这里查看。
该解决方案非常简单,最终,您将有两种不同的方法来锁定 DataGrid
列。
以下是我们创建冻结窗格效果的概要
- 创建一个简单的
DataGrid
,其中的数据被<div>
标签包围。 - 修改
DataGrid
以在标题行中呈现<th>
标签。 - 创建一个样式表,该样式表将锁定
DataGrid
标题行和列。 - 从客户端锁定列。
- 从服务器端锁定列。
使用代码
修改 DataGrid 以呈现 <th> 标签
我们遇到的第一个问题是 DataGrid
不会呈现 <th>
元素,而是在标题中呈现常见的 <td>
元素。幸运的是,微软为此发布了一个相当模糊的修补程序。我们大多数人已经在不知不觉中下载了此修补程序。您可以这里查看更多信息(或者如果您尚未下载,请下载)。
除了其他内容外,此修补程序还为 DataGrid
添加了属性 UseAccessibleHeader
。当此属性设置为 true
时,它将‘在带有 scope="col"
属性的 <th>
标签中呈现 DataGrid
表格标题。’
完成后的 DataGrid
代码将如下所示
<div id="div-datagrid">
<asp:DataGrid id="DataGrid1" runat="server" CssClass="Grid" UseAccessibleHeader="True">
<AlternatingItemStyle CssClass="GridAltRow"></AlternatingItemStyle>
<ItemStyle CssClass="GridRow"></ItemStyle>
<Columns>
<asp:BoundColumn DataField="Name" HeaderText="Name"
ItemStyle-Wrap="False"></asp:BoundColumn>
<asp:BoundColumn DataField="Address" HeaderText="Address"
ItemStyle-Wrap="False"></asp:BoundColumn>
<asp:BoundColumn DataField="City" HeaderText="City"
ItemStyle-Wrap="False"></asp:BoundColumn>
<asp:BoundColumn DataField="State" HeaderText="State"
ItemStyle-Wrap="False"></asp:BoundColumn>
<asp:BoundColumn DataField="Zip" HeaderText="Zip"
ItemStyle-Wrap="False"></asp:BoundColumn>
<asp:BoundColumn DataField="Random Babble"
HeaderText="Random Babble"
ItemStyle-Wrap="False"></asp:BoundColumn>
</Columns>
</asp:DataGrid>
</div>
创建样式表
样式表是该项目的关键。有两件事需要注意。首先,使用了 CSS 表达式。CSS 表达式在 Internet Explorer 5.0 中引入,它允许您将 JavaScript 表达式分配给 CSS 属性。在这种情况下,我们通过使用表达式来设置文档元素的水平和垂直滚动位置。其次,样式需要以一定的顺序设置。如果您更改下面列出的样式的顺序,您将得到一些相当奇怪的结果。如果您想知道...是的,我在实际想出一个有效的顺序之前,几乎尝试了每一个不正确的顺序。
这是 CSS 代码
/* Div container to wrap the datagrid */
div#div-datagrid {
width: 420px;
height: 200px;
overflow: auto;
scrollbar-base-color:#ffeaff;
}
/* Locks the left column */
td.locked, th.locked {
font-size: 14px;
font-weight: bold;
text-align: center;
background-color: navy;
color: white;
border-right: 1px solid silver;
position:relative;
cursor: default;
/*IE5+ only*/
left: expression(document.getElementById("div-datagrid").scrollLeft-2);
}
/* Locks table header */
th {
font-size: 14px;
font-weight: bold;
text-align: center;
background-color: navy;
color: white;
border-right: 1px solid silver;
position:relative;
cursor: default;
/*IE5+ only*/
top: expression(document.getElementById("div-datagrid").scrollTop-2);
z-index: 10;
}
/* Keeps the header as the top most item. Important for top left item*/
th.locked {z-index: 99;}
/* DataGrid Item and AlternatingItem Style*/
.GridRow {font-size: 10pt; color: black; font-family: Arial;
background-color:#ffffff; height:35px;}
.GridAltRow {font-size: 10pt; color: black; font-family: Arial;
background-color:#eeeeee; height:35px;}
从客户端锁定列
为了从客户端锁定列,我们只需要创建一个脚本,将第一列的样式更改为“locked
”。只需修改下面的代码即可冻结多列。以下脚本已添加到 ASPX 文件的头部以锁定第一列。
function lockCol(tblID) {
var table = document.getElementById(tblID);
var button = document.getElementById('toggle');
var cTR = table.getElementsByTagName('tr'); //collection of rows
if (table.rows[0].cells[0].className == '') {
for (i = 0; i < cTR.length; i++)
{
var tr = cTR.item(i);
tr.cells[0].className = 'locked'
}
button.innerText = "Unlock First Column";
} else {
for (i = 0; i < cTR.length; i++)
{
var tr = cTR.item(i);
tr.cells[0].className = ''
}
button.innerText = "Lock First Column";
}
}
从服务器端锁定列
同样,为了从服务器端锁定列,我们只需要将第一列的样式更改为“locked
”。为了实现这一点,我们使用 DataGrid
的 ItemDataBound
方法。以下代码将第一列的样式设置为“locked
”。这实际上非常简单,使用下面的代码
Sub Item_Bound(ByVal sender As Object, ByVal e As DataGridItemEventArgs) _
Handles DataGrid1.ItemDataBound
e.Item.Cells(0).CssClass = "locked"
End Sub
并且冻结前两列也同样容易
Sub Item_Bound(ByVal sender As Object, ByVal e As DataGridItemEventArgs) _
Handles DataGrid1.ItemDataBound
e.Item.Cells(0).CssClass = "locked"
e.Item.Cells(1).CssClass = "locked"
End Sub