介绍
平时使用GridView的时候会有固定表头、指定行或指定列的需求,就像Excel冻结行、列那样。其实我们可以用CSS来搞定。扩展一下GridView,通过设置几个属性来达到这样的功能。
控件开发
1、新建一个继承自GridView的类,另外为了保持滚动条状态,还要继承IPostBackDataHandler接口

/**//// <summary>
/// 继承自GridView
/// </summary>
[ToolboxData(@"<{0}:SmartGridView runat='server'></{0}:SmartGridView>")]
public class SmartGridView : GridView, IPostBackDataHandler

{

}

2、新建一个FixRowCol类,有七个属性
using System;
using System.Collections.Generic;
using System.Text;

using System.ComponentModel;

namespace YYControls.SmartGridView


{

/**//// <summary>
/// 固定表头、指定行或指定列的实体类
/// </summary>
[TypeConverter(typeof(ExpandableObjectConverter))]
public class FixRowCol

{
private bool _isFixHeader;

/**//// <summary>
/// 固定表头否?
/// </summary>
[Description("固定表头否?"), Category("扩展"), DefaultValue(false), NotifyParentProperty(true)]
public virtual bool IsFixHeader

{

get
{ return _isFixHeader; }

set
{ _isFixHeader = value; }
}

private bool _isFixPager;

/**//// <summary>
/// 固定分页行否?
/// </summary>
[Description("固定分页行否?"), Category("扩展"), DefaultValue(false), NotifyParentProperty(true)]
public virtual bool IsFixPager

{

get
{ return _isFixPager; }

set
{ _isFixPager = value; }
}

private string _fixRowIndices;

/**//// <summary>
/// 需要固定的行的索引(用逗号“,”分隔)
/// </summary>
[Description("需要固定的行的索引(用逗号“,”分隔)"), Category("扩展"), NotifyParentProperty(true)]
public virtual string FixRowIndices

{

get
{ return _fixRowIndices; }

set
{ _fixRowIndices = value; }
}

private string _fixColumnIndices;

/**//// <summary>
/// 需要固定的列的索引(用逗号“,”分隔)
/// </summary>
[Description("需要固定的列的索引(用逗号“,”分隔)"), Category("扩展"), NotifyParentProperty(true)]
public virtual string FixColumnIndices

{

get
{ return _fixColumnIndices; }

set
{ _fixColumnIndices = value; }
}

private System.Web.UI.WebControls.Unit _tableWidth;

/**//// <summary>
/// 表格的宽度
/// </summary>
[Description("表格的宽度"), Category("扩展"), NotifyParentProperty(true)]
public System.Web.UI.WebControls.Unit TableWidth

{

get
{ return _tableWidth; }

set
{ _tableWidth = value; }
}

private System.Web.UI.WebControls.Unit _tableHeight;

/**//// <summary>
/// 表格的高度
/// </summary>
[Description("表格的高度"), Category("扩展"), NotifyParentProperty(true)]
public System.Web.UI.WebControls.Unit TableHeight

{

get
{ return _tableHeight; }

set
{ _tableHeight = value; }
}

private bool _enableScrollState;

/**//// <summary>
/// 是否保持滚动条的状态
/// </summary>
[Description("是否保持滚动条的状态"), Category("扩展"), DefaultValue(false), NotifyParentProperty(true)]
public bool EnableScrollState

{

get
{ return _enableScrollState; }

set
{ _enableScrollState = value; }
}


/**//// <summary>
/// ToString();
/// </summary>
/// <returns></returns>
public override string ToString()

{
return "FixRowCol";
}
}
}

3、在继承自GridView的类中加一个复杂对象属性,该复杂对象就是第2步创建的那个FixRowCol
private FixRowCol _fixRowCol;

/**//// <summary>
/// 固定表头、指定行或指定列
/// </summary>
[
Description("固定表头、指定行或指定列"),
Category("扩展"),
DefaultValue(""),
DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
PersistenceMode(PersistenceMode.InnerProperty)
]
public virtual FixRowCol FixRowCol

{
get

{
if (_fixRowCol == null)

{
_fixRowCol = new FixRowCol();
}
return _fixRowCol;
}
}
4、重写OnRowDataBound以设置每个单元格的样式,从而实现固定表头、指定行或指定列的功能。

/**//// <summary>
/// OnRowDataBound
/// </summary>
/// <param name="e"></param>
protected override void OnRowDataBound(GridViewRowEventArgs e)

{
if (e.Row.RowType == DataControlRowType.Pager)

{
if (FixRowCol.IsFixPager)

{
if (this.PagerSettings.Position == PagerPosition.Top || (this.PagerSettings.Position == PagerPosition.TopAndBottom && _isTopPager))

{
// TopPager固定行和列
e.Row.Cells[0].Attributes.Add("style", "z-index:999; position: relative; top: expression(this.offsetParent.scrollTop); left: expression(this.offsetParent.scrollLeft);");
// 现在是TopPager,之后就是BottomPager了,所以设置_isTopPager为false
_isTopPager = false;
}
else if (this.PagerSettings.Position == PagerPosition.TopAndBottom && !_isTopPager)

{
// BottomPager只固定列
e.Row.Cells[0].Attributes.Add("style", "z-index:999; position: relative; left: expression(this.offsetParent.scrollLeft);");
// 现在是BottomPager,之后就是TopPager了,所以设置_isTopPager为true
_isTopPager = true;
}
}
}

if (e.Row.RowType == DataControlRowType.DataRow || e.Row.RowType == DataControlRowType.Header)

{
// 给每一个指定固定的列的单元格加上css属性
if (!String.IsNullOrEmpty(FixRowCol.FixColumnIndices))

{
// 列索引
foreach (string s in FixRowCol.FixColumnIndices.Split(','))

{
int i;
if (!Int32.TryParse(s, out i))
throw new ArgumentException("FixColumnIndices", "含有非整形的字符");
if (i > e.Row.Cells.Count)
throw new ArgumentOutOfRangeException("FixColumnIndices", "溢出");

e.Row.Cells[i].Attributes.Add("style", "position: relative; left: expression(this.offsetParent.scrollLeft);");
}
}

bool isFixRow = false; // 当前行是否固定
if (FixRowCol.IsFixHeader && e.Row.RowType == DataControlRowType.Header)

{
isFixRow = true;
}

if (!String.IsNullOrEmpty(FixRowCol.FixRowIndices) && e.Row.RowType == DataControlRowType.DataRow)

{
// 行索引
foreach (string s in FixRowCol.FixRowIndices.Split(','))

{
int i;
if (!Int32.TryParse(s, out i))
throw new ArgumentException("FixRowIndices", "含有非整形的字符");
if (i > e.Row.Cells.Count)
throw new ArgumentOutOfRangeException("FixRowIndices", "溢出");

if (i == e.Row.RowIndex)

{
isFixRow = true;
break;
}
}
}

// 固定该行
if (isFixRow)

{
// 该行的每一个单元格
for (int j = 0; j < e.Row.Cells.Count; j++)

{
// 该单元格不属于固定列
if (String.IsNullOrEmpty(e.Row.Cells[j].Attributes["style"]) || e.Row.Cells[j].Attributes["style"].IndexOf("position: relative;") == -1)

{
e.Row.Cells[j].Attributes.Add("style", " position: relative; top: expression(this.offsetParent.scrollTop);");
}
// 该单元格属于固定列
else

{
e.Row.Cells[j].Attributes.Add("style", e.Row.Cells[j].Attributes["style"] + "top: expression(this.offsetParent.scrollTop); z-index: 666;");
}
}
}
}

base.OnRowDataBound(e);
}

5、增