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

来源:互联网 发布:mac os固件验证错误 编辑:程序博客网 时间:2024/05/23 12:10

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

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

本控件最终效果图:

以下是ScrollGridView的源代码:

<span style="color:#00ff;">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    }}</span>

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>

原创粉丝点击