1. WinForm:
首先需要编写一个类来表示自画的表头,这个类将记录表头的显示文本、图标和属于它管辖的列的信息。
using
System;
using System.Collections;
using System.Drawing;
namespace example
{
///
/// 表头类
///
public class TopHeaderColumn
{
public TopHeaderColumn()
{
columnCollection = new ArrayList();
}
// 用于记录表头管辖的各列的信息
private ArrayList columnCollection;
public ArrayList ColumnCollection
{
get
{
return columnCollection;
}
set
{
columnCollection = value;
}
}
// 表头的显示文本
private string caption;
public string Caption
{
get
{
return caption;
}
set
{
caption = value;
}
}
// 表头的宽度
private int width;
public int Width
{
get
{
return width;
}
set
{
width = value;
}
}
// 表头的图表
private Image image = null ;
public Image Image
{
get
{
return image;
}
set
{
image = value;
}
}
}
}
using System.Collections;
using System.Drawing;
namespace example
{
///
/// 表头类
///
public class TopHeaderColumn
{
public TopHeaderColumn()
{
columnCollection = new ArrayList();
}
// 用于记录表头管辖的各列的信息
private ArrayList columnCollection;
public ArrayList ColumnCollection
{
get
{
return columnCollection;
}
set
{
columnCollection = value;
}
}
// 表头的显示文本
private string caption;
public string Caption
{
get
{
return caption;
}
set
{
caption = value;
}
}
// 表头的宽度
private int width;
public int Width
{
get
{
return width;
}
set
{
width = value;
}
}
// 表头的图表
private Image image = null ;
public Image Image
{
get
{
return image;
}
set
{
image = value;
}
}
}
}
另外,因为以后的代码需要DataGrid水平滚动条的位置,而DataGrid无法取得水平滚动条的位置,所以需要对DataGrid做一点修改。编写基于DataGrid控件的新控件myData.
public
class
myDataGrid:DataGrid
{
// 取得水平滚动条的位置
public ScrollBar HScrollBar
{
get
{
return HorizScrollBar;
}
}
}
{
// 取得水平滚动条的位置
public ScrollBar HScrollBar
{
get
{
return HorizScrollBar;
}
}
}
好了,可以工作了。在工具箱加入加入myDataGrid,新建一个Window应用程序,一个myDataGrid和ImageList,连接SQL数据库NorthWind。当然,还得加入上面的TopHeaderColumn类。
private
void
Bind()
... {
SqlConnection con=new SqlConnection("server=.;uid=sa;pwd=;database=northwind;");
con.Open();
SqlDataAdapter sda=new SqlDataAdapter();
sda.SelectCommand=new SqlCommand("select lastname,firstname,Address,city from employees",con);
DataSet ds=new DataSet();
sda.Fill(ds,"employees");
dgData.DataSource=ds;
dgData.DataMember="employees";
//设置DataGrid的各列
DataGridTextBoxColumn c1=new DataGridTextBoxColumn();
DataGridTextBoxColumn c2=new DataGridTextBoxColumn();
DataGridTextBoxColumn c3=new DataGridTextBoxColumn();
DataGridTextBoxColumn c4=new DataGridTextBoxColumn();
c1.MappingName="lastname";
c2.MappingName="firstname";
c3.MappingName="Address";
c4.MappingName="city";
c1.HeaderText="lastname";
c2.HeaderText="firstname";
c3.HeaderText="Address";
c4.HeaderText="city";
c1.WidthChanged+=new EventHandler(this.abc);
c2.WidthChanged+=new EventHandler(this.abc);
c3.WidthChanged+=new EventHandler(this.abc);
c4.WidthChanged+=new EventHandler(this.abc);
DataGridTableStyle dts=new DataGridTableStyle();
dts.GridColumnStyles.Add(c1);
dts.GridColumnStyles.Add(c2);
dts.GridColumnStyles.Add(c3);
dts.GridColumnStyles.Add(c4);
dts.MappingName="employees";
dgData.TableStyles.Add(dts);
//建立自画的表头类并将它们加入集合al
al=new ArrayList();
TopHeaderColumn tc1=new TopHeaderColumn();
tc1.Caption="Name";
tc1.Image=imageList1.Images[0];
//记录它管辖列的index
tc1.ColumnCollection.Add(0);
tc1.ColumnCollection.Add(1);
tc1.Width=c1.Width+c2.Width;
TopHeaderColumn tc2=new TopHeaderColumn();
tc2.Caption="Address";
tc2.Image=imageList1.Images[1];
tc2.ColumnCollection.Add(2);
tc2.ColumnCollection.Add(3);
tc2.Width=c3.Width+c4.Width;
al.Add(tc1);
al.Add(tc2);
dgData.Paint+=new PaintEventHandler(dgData_Paint);
}
private void dgData_Paint( object sender,System.Windows.Forms.PaintEventArgs e)
... {
int x=0;
//计算出第一个表头的左边距
int left=dgData.TableStyles[0].RowHeaderWidth-dgData.HScrollBar.Value;
//遍利表头集合al,画出表头
foreach(object o in al)
...{
//计算出表头文字的左边距
x=left+(((TopHeaderColumn)o).Width-Convert.ToInt32(e.Graphics.MeasureString(((TopHeaderColumn)o).Caption,dgData.CaptionFont).Width))/2;
//完成表头绘制
if(((TopHeaderColumn)o).Image!=null)
e.Graphics.DrawImage(((TopHeaderColumn)o).Image,x-imageList1.Images[0].Size.Width,0);
e.Graphics.DrawString(((TopHeaderColumn)o).Caption,dgData.CaptionFont,new SolidBrush(dgData.CaptionForeColor),x,0);
if(x>0)
e.Graphics.DrawLine(new Pen(Color.Black,2),left-1,0,left-1,dgData.Height);
//计算下一个表头的左边距
left+=((TopHeaderColumn)o).Width;
}
if(x e.Graphics.DrawLine(new Pen(Color.Black,2),left-1,0,left-1,dgData.Height);
}
private void abc( object sender,EventArgs e)
... {
//设置表头的宽度
foreach(object o in al)
...{
((TopHeaderColumn)o).Width=0;
foreach(int i in ((TopHeaderColumn)o).ColumnCollection)
...{
((TopHeaderColumn)o).Width+=dgData.TableStyles[0].GridColumnStyles[i].Width;
}
}
}
... {
SqlConnection con=new SqlConnection("server=.;uid=sa;pwd=;database=northwind;");
con.Open();
SqlDataAdapter sda=new SqlDataAdapter();
sda.SelectCommand=new SqlCommand("select lastname,firstname,Address,city from employees",con);
DataSet ds=new DataSet();
sda.Fill(ds,"employees");
dgData.DataSource=ds;
dgData.DataMember="employees";
//设置DataGrid的各列
DataGridTextBoxColumn c1=new DataGridTextBoxColumn();
DataGridTextBoxColumn c2=new DataGridTextBoxColumn();
DataGridTextBoxColumn c3=new DataGridTextBoxColumn();
DataGridTextBoxColumn c4=new DataGridTextBoxColumn();
c1.MappingName="lastname";
c2.MappingName="firstname";
c3.MappingName="Address";
c4.MappingName="city";
c1.HeaderText="lastname";
c2.HeaderText="firstname";
c3.HeaderText="Address";
c4.HeaderText="city";
c1.WidthChanged+=new EventHandler(this.abc);
c2.WidthChanged+=new EventHandler(this.abc);
c3.WidthChanged+=new EventHandler(this.abc);
c4.WidthChanged+=new EventHandler(this.abc);
DataGridTableStyle dts=new DataGridTableStyle();
dts.GridColumnStyles.Add(c1);
dts.GridColumnStyles.Add(c2);
dts.GridColumnStyles.Add(c3);
dts.GridColumnStyles.Add(c4);
dts.MappingName="employees";
dgData.TableStyles.Add(dts);
//建立自画的表头类并将它们加入集合al
al=new ArrayList();
TopHeaderColumn tc1=new TopHeaderColumn();
tc1.Caption="Name";
tc1.Image=imageList1.Images[0];
//记录它管辖列的index
tc1.ColumnCollection.Add(0);
tc1.ColumnCollection.Add(1);
tc1.Width=c1.Width+c2.Width;
TopHeaderColumn tc2=new TopHeaderColumn();
tc2.Caption="Address";
tc2.Image=imageList1.Images[1];
tc2.ColumnCollection.Add(2);
tc2.ColumnCollection.Add(3);
tc2.Width=c3.Width+c4.Width;
al.Add(tc1);
al.Add(tc2);
dgData.Paint+=new PaintEventHandler(dgData_Paint);
}
private void dgData_Paint( object sender,System.Windows.Forms.PaintEventArgs e)
... {
int x=0;
//计算出第一个表头的左边距
int left=dgData.TableStyles[0].RowHeaderWidth-dgData.HScrollBar.Value;
//遍利表头集合al,画出表头
foreach(object o in al)
...{
//计算出表头文字的左边距
x=left+(((TopHeaderColumn)o).Width-Convert.ToInt32(e.Graphics.MeasureString(((TopHeaderColumn)o).Caption,dgData.CaptionFont).Width))/2;
//完成表头绘制
if(((TopHeaderColumn)o).Image!=null)
e.Graphics.DrawImage(((TopHeaderColumn)o).Image,x-imageList1.Images[0].Size.Width,0);
e.Graphics.DrawString(((TopHeaderColumn)o).Caption,dgData.CaptionFont,new SolidBrush(dgData.CaptionForeColor),x,0);
if(x>0)
e.Graphics.DrawLine(new Pen(Color.Black,2),left-1,0,left-1,dgData.Height);
//计算下一个表头的左边距
left+=((TopHeaderColumn)o).Width;
}
if(x e.Graphics.DrawLine(new Pen(Color.Black,2),left-1,0,left-1,dgData.Height);
}
private void abc( object sender,EventArgs e)
... {
//设置表头的宽度
foreach(object o in al)
...{
((TopHeaderColumn)o).Width=0;
foreach(int i in ((TopHeaderColumn)o).ColumnCollection)
...{
((TopHeaderColumn)o).Width+=dgData.TableStyles[0].GridColumnStyles[i].Width;
}
}
}
好了,完成,运行下试试。上面的代码实现了两层表头,至于三层表头也同理。其中:sda.Fill(ds,"employees");如果写成sda.Fill(ds);的话,.net会提示你无法创建employees的子列表。
2. WebFrom:
WebForm下就更简单了。实际上Asp.Net下的DataGrid只不过是一个HtmlTable,只不过在HtmlTable的基础上添加了很多属性、方法,纳入ViewState机制,来生成、控制它;有了这一点认识,事情就很好办了:适用有模版列。
DataGrid的ItemCreated事件中处理:
if
(e.Item.ItemType
==
ListItemType.Header)
{
TableCellCollection tcl = e.Item.Cells;
tcl.Clear();
tcl.Add( new TableHeaderCell());
tcl[ 0 ].RowSpan = 2 ;
tcl[ 0 ].Text = " No. " ;
tcl.Add( new TableHeaderCell());
tcl[ 1 ].RowSpan = 2 ;
tcl[ 1 ].Text = " <input id='chkSelAll' type='checkbox' name='chkSelAll' οnclick='javascript:CheckAll(Form1,this.checked);'/> " ;
tcl.Add( new TableHeaderCell());
tcl[ 2 ].RowSpan = 2 ;
tcl[ 2 ].Text = " 修改 " ;
tcl.Add( new TableHeaderCell());
tcl[ 3 ].RowSpan = 2 ;
tcl[ 3 ].Text = " 物业项目 " ;
tcl.Add( new TableHeaderCell());
tcl[ 4 ].RowSpan = 2 ;
tcl[ 4 ].Text = " 对应帐套 " ;
tcl.Add( new TableHeaderCell());
tcl[ 5 ].RowSpan = 2 ;
tcl[ 5 ].Text = " 收费项目 " ;
tcl.Add( new TableHeaderCell());
tcl[ 6 ].ColumnSpan = 2 ;
tcl[ 6 ].Text = " 本期收入</td><td colspan=2>预收</td></tr><tr style='color:Black;background-color:#BFBFBF;font-size:9pt;font-weight:bold;'><td>对应会计科目</td><td>对应税金科目</td><td>对应会计科目</td><td>对应税金科目 " ;
}
{
TableCellCollection tcl = e.Item.Cells;
tcl.Clear();
tcl.Add( new TableHeaderCell());
tcl[ 0 ].RowSpan = 2 ;
tcl[ 0 ].Text = " No. " ;
tcl.Add( new TableHeaderCell());
tcl[ 1 ].RowSpan = 2 ;
tcl[ 1 ].Text = " <input id='chkSelAll' type='checkbox' name='chkSelAll' οnclick='javascript:CheckAll(Form1,this.checked);'/> " ;
tcl.Add( new TableHeaderCell());
tcl[ 2 ].RowSpan = 2 ;
tcl[ 2 ].Text = " 修改 " ;
tcl.Add( new TableHeaderCell());
tcl[ 3 ].RowSpan = 2 ;
tcl[ 3 ].Text = " 物业项目 " ;
tcl.Add( new TableHeaderCell());
tcl[ 4 ].RowSpan = 2 ;
tcl[ 4 ].Text = " 对应帐套 " ;
tcl.Add( new TableHeaderCell());
tcl[ 5 ].RowSpan = 2 ;
tcl[ 5 ].Text = " 收费项目 " ;
tcl.Add( new TableHeaderCell());
tcl[ 6 ].ColumnSpan = 2 ;
tcl[ 6 ].Text = " 本期收入</td><td colspan=2>预收</td></tr><tr style='color:Black;background-color:#BFBFBF;font-size:9pt;font-weight:bold;'><td>对应会计科目</td><td>对应税金科目</td><td>对应会计科目</td><td>对应税金科目 " ;
}