ASP.NET控件开发之ScrollGridView(兼容FF、IE、苹果、谷歌、搜狗等浏览器。固定表头滚动的GridView控件)...

这篇文章本来在2个月前就应该写了的,只是一直没有找到好的解决方案,所以迟迟没有动笔,直到今天,才找到了比较满意的解决方案。

网上关于固定GridView表头,常见的有两种解决方案,一种是采用css样式,一种则是使用js代码。我再后面贴出了网上常用的解决方案,不过这两种解决方案都无法从根本上解决问题,并且还有一个致命的缺点,那就是在FF中不支持,我认为采用jquery重写表头扩展GridView才是釜底抽薪的解决办法。记得在网上有一个固定表头的GridView扩展控件,不过这个控件在Update下面一回发就会报错。我这个控件是在GridViewFixedHeaderExtender控件之上进行了改良的,因为我发现GridViewFixedHeaderExtender在IE9中页面第一次加载的时候表头布局会乱,经过我一番研究,发现这是因为在IE9中它的相对定位出了问题,苦思了一整天,终于想出了一个好的解决方案,在IE9中,对其进行特别处理,表头的外层设置为相对定位,内层设置为绝对定位,这样就一切oK了。

本控件最终效果图:

以下是ScrollGridView的源代码:

using System; using System.Collections.Generic; using System.Text; using System.Web.UI; using System.Web.UI.WebControls; using System.ComponentModel; using System.Web; using System.Security.Permissions; [assembly: WebResource("SureKAM.SPM.Portal.Controls.Resources.Script.GridViewFixedHeaderExtender.js", "application/x-javascript", PerformSubstitution = true)] namespace SureKAM.SPM.Portal.Controls { [ AspNetHostingPermission(SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal), AspNetHostingPermission(SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal), Designer("SureKAM.SPM.Portal.Controls.SimpleDesigner, SureKAM.SPM.Portal.Controls"), ToolboxData("<{0}:GridViewFixedHeaderExtender runat=server></{0}:GridViewFixedHeaderExtender>"), TargetControlType(typeof(GridView)) ] public class GridViewFixedHeaderExtender : ExtenderControl { #region Overrides protected override void OnLoad(EventArgs e) { base.OnLoad(e); } protected override IEnumerable<ScriptDescriptor> GetScriptDescriptors(Control targetControl) { if (TargetControl == null || !TargetControl.Visible || TargetControl.Rows.Count == 0) { TargetControl.Height = Unit.Empty; yield break; } ScriptBehaviorDescriptor descriptor = new ScriptBehaviorDescriptor("SureKAM.SPM.Portal.Controls.GridViewFixedHeaderExtender", targetControl.ClientID); descriptor.AddProperty("scrollField", HiddenFieldID); yield return descriptor; } protected override IEnumerable<ScriptReference> GetScriptReferences() { if (TargetControl == null || !TargetControl.Visible || TargetControl.Rows.Count == 0) { TargetControl.Height = Unit.Empty; yield break; } yield return new ScriptReference("SureKAM.SPM.Portal.Controls.Resources.Script.GridViewFixedHeaderExtender.js", this.GetType().Assembly.FullName); } protected override void Render(HtmlTextWriter writer) { ScriptManager.RegisterHiddenField( this, HiddenFieldID, LastScroll.ToString() ); base.Render(writer); } private GridView TargetControl { get { GridView result = this.NamingContainer.FindControl(TargetControlID) as GridView; return result; } } private int LastScroll { get { int result = 0; if (Page.Request[HiddenFieldID] != null) { int.TryParse(Page.Request[HiddenFieldID], out result); } return result; } } private string HiddenFieldID { get { return String.Format("{0}_GVFHE_Scroll", ClientID); } } #endregion } }

js代码如下:

/// <reference name="MicrosoftAjax.debug.js" /> /// <reference name="MicrosoftAjaxTimer.debug.js" /> /// <reference name="MicrosoftAjaxWebForms.debug.js" /> Type.registerNamespace("SureKAM.SPM.Portal.Controls"); SureKAM.SPM.Portal.Controls.GridViewFixedHeaderExtender = function (element) { SureKAM.SPM.Portal.Controls.GridViewFixedHeaderExtender.initializeBase(this, [element]); this._documentResizeDelegate = null; this._lock = false; this._mainTableID = null; this._innerTableID = null; this._divChild = null; this._scrollField = 0; } SureKAM.SPM.Portal.Controls.GridViewFixedHeaderExtender.prototype = { // Overrides //#region initialize: function () { SureKAM.SPM.Portal.Controls.GridViewFixedHeaderExtender.callBaseMethod(this, 'initialize'); this.initGrid(); }, dispose: function () { //Add custom dispose actions here $removeHandler(window, "resize", this._documentResizeDelegate); if (this._divChild) { $clearHandlers(this._divChild); } SureKAM.SPM.Portal.Controls.GridViewFixedHeaderExtender.callBaseMethod(this, 'dispose'); }, //#endregion // Properties //#region get_scrollField: function () { return this._scrollField; }, set_scrollField: function (value) { if (this._scrollField !== value) { this._scrollField = value; this.raisePropertyChanged('scrollField'); } }, //#endregion // Methods //#region getLastScroll: function () { var result = 0; var hf = $get(this._scrollField); if (hf) { result = parseInt(hf.value); if (!result) result = 0; } return result; }, setLastScroll: function (value) { var hf = $get(this._scrollField); if (hf) { hf.value = value; } }, initGrid: function () { // create deep clone of target grid var target = this.get_element(); var clone = target.cloneNode(true); // get desired height of inner scrollable area var height = target.style.height; var width = target.style.width; var mainTable = target.cloneNode(false); mainTable.style.position = "relative"; mainTable.id = String.format("outer_{0}", target.id); target.parentNode.insertBefore(mainTable, target); var header = target.rows[0].cloneNode(true); if (navigator.appName == "Microsoft Internet Explorer" && navigator.appVersion.split(";")[1].replace(/[ ]/g, "") == "MSIE9.0") { var headDiv = document.createElement("div"); headDiv.style.position = "relative"; headDiv.style.width = "100%"; var mainHead = document.createElement("thead"); mainHead.style.position = "absolute"; headDiv.appendChild(mainHead); mainTable.appendChild(headDiv); var div = document.createElement("div"); div.style.height = target.rows[0].style.height; div.style.width = target.rows[0].style.width; //div.style.minWidth = target.rows[0].style.width; //div.style.position = "static"; mainTable.appendChild(div); } else { var mainHead = document.createElement("thead"); mainTable.appendChild(mainHead); } var mainBody = document.createElement("tbody"); mainTable.appendChild(mainBody); // Clone original header //var header = target.rows[0].cloneNode(true); mainHead.appendChild(header); // add scrollable area mainTable var secondRow = document.createElement("tr"); mainBody.appendChild(secondRow); var mainTd = document.createElement("td"); secondRow.appendChild(mainTd) this.setAttribute(mainTd, "colspan", target.rows[0].cells.length); this.setAttribute(mainTd, "align", "left"); this.setAttribute(mainTd, "valign", "top"); var divChild = document.createElement("div"); mainTd.appendChild(divChild); divChild.style.width = width; divChild.style.height = height; $addHandler(divChild, "scroll", Function.createDelegate(this, this.syncScroll)); divChild.style.overflow = "auto"; divChild.style.overflowX = "hidden"; divChild.style.overflowY = "scroll"; this._divChild = divChild; // Sys.UI.DomElement.addCssClass(divChild, "divScrollVertical"); // now remove old grid from document and insert new clone into the place target.parentNode.removeChild(target); divChild.appendChild(clone); // assign extender related data to clone clone._behaviors = target._behaviors; clone.GridViewFixedHeaderExtender = target.GridViewFixedHeaderExtender; // correct styles var attributes = []; for (var i = 0; i < clone.attributes.length; i++) { var attr = clone.attributes.item(i); var value = attr.value.trim().toLowerCase(); if (value != "cellpadding" && value != "cellspacing") { Array.add(attributes, attr); } } Array.forEach(attributes, this.deleteAttribute, clone); clone.deleteRow(clone.rows[0]); clone.border = "0"; clone.style.borderWidth = "0px"; //clone.style.width = "100%"; clone.style.height = ""; mainTable.style.height = ""; target.style.height = ""; // correct widths of header columns and subscribe to document resize event: this._mainTableID = mainTable.id; this._innerTableID = clone.id; this._documentResizeDelegate = Function.createDelegate( this, this.syncWidths ); this._documentResizeDelegate.call(); // Attach to window's resize event to resize header cells when inner cells change their size $addHandler(window, "resize", this._documentResizeDelegate); // Restore scroll position from last time divChild.scrollTop = this.getLastScroll(); }, setAttribute: function (element, attribute, value) { var namedItem = document.createAttribute(attribute); namedItem.value = value; element.attributes.setNamedItem(namedItem); }, deleteAttribute: function (attribute, index, attributes) { this.removeAttribute(attribute); }, syncScroll: function (args) { if (this._divChild) { this.setLastScroll(this._divChild.scrollTop); } }, syncWidths: function (args) { if (!this._lock) { this._lock = true; var mainTable = $get(this._mainTableID); var innerCellPadding = mainTable.cellPadding; var header = mainTable.rows[0]; var innerTable = $get(this._innerTableID); var originalRow = innerTable.rows[0]; var headerWidth = Sys.UI.DomElement.getBounds(header).width; var originalRowWidth = Sys.UI.DomElement.getBounds(originalRow).width; var diff = headerWidth - originalRowWidth - innerCellPadding * 2; if (originalRow && header) { for (var i = 0; i < originalRow.cells.length; i++) { var bounds = Sys.UI.DomElement.getBounds(originalRow.cells[i]); var x = bounds.width; if (i == originalRow.cells.length - 1) { x = x + diff - innerCellPadding * 2; } else { x = x - innerCellPadding; } if (navigator.appName == "Microsoft Internet Explorer" && navigator.appVersion.split(";")[1].replace(/[ ]/g, "") == "MSIE9.0") { } else { header.cells[i].style.width = x + "px"; } } } this._lock = false; } } //#endregion } SureKAM.SPM.Portal.Controls.GridViewFixedHeaderExtender.registerClass('SureKAM.SPM.Portal.Controls.GridViewFixedHeaderExtender', Sys.UI.Behavior);

1,样式固定。

这个方法是从网上参考的,但是忘记了来源,使用之后发现效果不是很好,有闪动,并且在FF浏览器中不支持。以下是源码(来源于网络):


<style type="text/css">
.Freezing
{
position:relative;
table-layout:fixed;
top:expression(this.offsetParent.scrollTop);
z-index:10;
}
.Freezing th{text-overflow:ellipsis;overflow:hidden;white-space:nowrap;padding:2px;}
</style>

2,Javascript方法。

也是网上参考,搜索应该比较多,据网友回帖说是效果很好,自己使用效果不好。以下是源码分析

// 创建表头
if (document.getElementById( " gvTitle " ) == null )
{
var gdvList = document.getElementById( " gvCommon " );
var gdvHeader = gdvList.cloneNode( true );
gdvHeader.id = " gvTitle " ;
for (i = gdvHeader.rows.length - 1 ; i > 0 ;i -- )
{
gdvHeader.deleteRow(i);
}
document.getElementById( " divTitle " ).appendChild(gdvHeader);
var div = document.getElementById( " divGvData " );
var tbl = document.getElementById( " divTitle " );
tbl.style.position = " absolute " ;
tbl.style.zIndex = 100 ;
tbl.style.top = div.offsetTop;
tbl.style.left = div.offsetLeft;
}

大致做法是利用JS方法Copy出一个表头 gdvHeader 放在一个“divTitle”的DIV中。

GridView是包含在“divGvData”DIV中的,然后设置divTitle的页面位置和divGvData的一致,也就是覆盖在上面。 目前发现效果还行。有一点要注意,gdvHeader.id = "gvTitle";要重新设置一个ID,不然删除的还是GridView的数据行。缺点:FF中不支持。

HTML中的部分代码:

< div id ="divTitle" style ="position:relative; top:0; left:0; overflow:hidden; width:978px; border:0px solid red;" ></ div >
< div id ="divGvData" runat ="server" style ="position:relative; top:0px; left:0px; overflow:scroll; width:994px;height:450px;" onscroll ="funGrilViewScroll(); return false;" >
< asp:GridView ID ="gvCommon" style ="position:relative; top:0px; left:0px;" runat ="server" CssClass ="gvFixd" BackColor ="White" BorderColor ="#999999" BorderStyle ="None" BorderWidth ="1px" CellPadding ="3" AutoGenerateColumns ="False" GridLines ="Vertical" PageSize ="5" AllowSorting ="True" OnSorting ="gvCommon_Sorting" >
< FooterStyle BackColor ="#CCCCCC" ForeColor ="Black" />
< RowStyle BackColor ="#E7E7FF" ForeColor ="Black" Font-Size ="Small" />
< HeaderStyle HorizontalAlign ="Center" BackColor ="#000084" BorderColor ="White" BorderWidth ="1px" BorderStyle ="Solid" Font-Bold ="True" ForeColor ="White" />
</ asp:GridView >
</ div >

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值