有個簡易的方法:
2,添加CellPainting,代碼如下:
{
if (e.RowIndex == - 1)
{
// int w = dataGridView1.HorizontalScrollingOffset + dataGridView1.TopLeftHeaderCell.Size.Width + dataGridView1.Columns[0].Width + 10;
Rectangle newRect = new Rectangle(e.CellBounds.X + 1,
e.CellBounds.Y + 1, e.CellBounds.Width - 4,
e.CellBounds.Height - 4);
using (
Brush gridBrush = new SolidBrush( this.GridColor),
backColorBrush = new SolidBrush(e.CellStyle.BackColor))
{
using (Pen gridLinePen = new Pen(gridBrush))
{
// Erase the cell.
e.Graphics.FillRectangle(backColorBrush, e.CellBounds);
// Draw the grid lines (only the right and bottom lines;
// DataGridView takes care of the others).
e.Graphics.DrawLine(gridLinePen, e.CellBounds.Left,
e.CellBounds.Bottom - 1, e.CellBounds.Right - 1,
e.CellBounds.Bottom - 1);
if (e.ColumnIndex > - 1 && topRow != null && topRow.Cells[e.ColumnIndex].ColSpan > 1)
{
e.Graphics.DrawLine(gridLinePen, e.CellBounds.Right - 1,
e.CellBounds.Top + e.ClipBounds.Height / 2, e.CellBounds.Right - 1,
e.CellBounds.Bottom);
}
else
{
e.Graphics.DrawLine(gridLinePen, e.CellBounds.Right - 1,
e.CellBounds.Top, e.CellBounds.Right - 1,
e.CellBounds.Bottom);
}
// Draw the inset highlight box.
// e.Graphics.DrawRectangle(Pens.Blue, newRect);
int scale = e.CellBounds.Height / 3;
if (e.ColumnIndex > - 1 && topRow.Cells[e.ColumnIndex].Text != null)
{
scale = e.CellBounds.Height / 2;
e.Graphics.DrawLine(gridLinePen, e.CellBounds.Left, e.CellBounds.Bottom - e.CellBounds.Height / 2, e.CellBounds.Right, e.CellBounds.Bottom - e.CellBounds.Height / 2);
}
// Draw the text content of the cell, ignoring alignment.
if (e.Value != null)
{
e.Graphics.DrawString(e.Value.ToString(), e.CellStyle.Font,
Brushes.Crimson, e.CellBounds.X + 2,
e.CellBounds.Y + scale + 2, StringFormat.GenericDefault);
}
if (e.ColumnIndex > - 1 && topRow.Cells[e.ColumnIndex].RelateIndex > - 1 && topRow.Cells[e.ColumnIndex].Text != null)
{
Rectangle recCell = new Rectangle(e.CellBounds.X - 1 - topRow.Cells[e.ColumnIndex].SpanRowWith,
e.CellBounds.Y + 1, topRow.Cells[e.ColumnIndex].SpanRowWith,
e.CellBounds.Height / 2);
StringFormat sf = new StringFormat();
sf.Alignment = StringAlignment.Center;
e.Graphics.DrawString(topRow.Cells[e.ColumnIndex].Text, e.CellStyle.Font, Brushes.Crimson, recCell, sf);
}
e.Handled = true;
}
}
}
}







至於表尾合計,也做出了原型。二維表頭+表尾合計,基本上滿足需求了。
url:http://greatverve.cnblogs.com/archive/2012/03/05/Multi-DataGridView.html
1.DataGridView實現課程表 testcontrol.rar
2.DataGridView二維表頭及單元格合並 DataGridView單元格合並和二維表頭.rar myMultiColHeaderDgv.rar
3.DataGridView單元格顯示GIF圖片 gifanimationindatagrid.rar
4.自定義顯示DataGridView列(行頭顯示行號與圖標,同一單元格顯示圖片也顯示文字)TestDataGridViewRowStyle2.rar
5.擴展DataGridView功能
相關文章
CheckBox Header Column For DataGridView
DataGridView填充、更新、刪除(多行)Sql Express 2005數據庫
DataGridView擴展的一些想法(二維表頭、合並單元格、合計行)
DataGridView分頁功能的實現
在DataGridView控件中加入ComboBox下拉列表框的實現
DataGridView中虛擬模式(Virtual Mode)的使用
從 DataGridView 控件 托放數據 到 TreeView控件
相關一些資料下載(收集自網絡)
微軟提供的例子 datagridviewsamples.rar
DataGridView使用文檔 DataGridView_Doc.rar
Excel與DataGridView互導數據 Excl導入datagridview.rar
DataGridView擴展功能代碼
--------------------------------------------------------------------------
還有用第三方控件的:
在做信息管理系統時,很多中式報表都是多維的,要實現報表數據顯示,通常要用到多維表頭。然而,非常遺憾的是,Winform中DataGrid、DataGridView本身不提供多維表頭設計,要實現多維報表只好利用第三方的控件。通過對DataGridView的擴展,利用標題行進行重繪,可實現多維表頭的友好界面。下面是對多維表頭的探討和實現。
1、常用多表頭制作方法
a.第三方控件實現多維表頭:FlexGrid--展示效果很好,就是數據量大加載時顯示速度較慢。
b.報表方式實現多維表頭:CrystalReport、Grid++Report--通過預覽方式實現數據顯示
c、DataGridView實現多維表頭
2、DataGridView多維表頭實現原理
通過重繪標題欄進行多欄實現,通過RowSpan和ColSpan來進行合並,類似Html的Table實現方式。
3、調用方法

private void Form1_Load(object sender, EventArgs e)
{
InitDataTable();
InitDataGridView();
}
DataTable table = new DataTable();
private void InitDataTable()
{
DataColumn col;
col = new DataColumn();
col.ColumnName = "客戶名稱";
table.Columns.Add(col);
col = new DataColumn();
col.ColumnName = "產品名稱";
table.Columns.Add(col);
col = new DataColumn();
col.ColumnName = "規格";
table.Columns.Add(col);
col = new DataColumn();
col.ColumnName = "單位";
table.Columns.Add(col);
col = new DataColumn();
col.ColumnName = "期初存貨數量";
col.DataType = System.Type.GetType("System.Decimal");
table.Columns.Add(col);
col = new DataColumn();
col.ColumnName = "期初貨款";
col.DataType = System.Type.GetType("System.Decimal");
table.Columns.Add(col);
col = new DataColumn();
col.ColumnName = "期初帳款";
col.DataType = System.Type.GetType("System.Decimal");
table.Columns.Add(col);
col = new DataColumn();
col.ColumnName = "發貨數量";
col.DataType = System.Type.GetType("System.Decimal");
table.Columns.Add(col);
col = new DataColumn();
col.ColumnName = "發貨金額";
col.DataType = System.Type.GetType("System.Decimal");
table.Columns.Add(col);
col = new DataColumn();
col.ColumnName = "開票數量";
col.DataType = System.Type.GetType("System.Decimal");
table.Columns.Add(col);
col = new DataColumn();
col.ColumnName = "開票金額";
col.DataType = System.Type.GetType("System.Decimal");
table.Columns.Add(col);
col = new DataColumn();
col.ColumnName = "回款數量";
col.DataType = System.Type.GetType("System.Decimal");
table.Columns.Add(col);
col = new DataColumn();
col.DataType = System.Type.GetType("System.Decimal");
col.ColumnName = "回款金額";
table.Columns.Add(col);
col = new DataColumn();
col.DataType = System.Type.GetType("System.Decimal");
col.ColumnName = "未開票回款數量";
table.Columns.Add(col);
col = new DataColumn();
col.DataType = System.Type.GetType("System.Decimal");
col.ColumnName = "未開票回款金額";
table.Columns.Add(col);
col = new DataColumn();
col.DataType = System.Type.GetType("System.Decimal");
col.ColumnName = "期末存貨數量";
table.Columns.Add(col);
col = new DataColumn();
col.DataType = System.Type.GetType("System.Decimal");
col.ColumnName = "期末應收貨款";
table.Columns.Add(col);
col = new DataColumn();
col.DataType = System.Type.GetType("System.Decimal");
col.ColumnName = "期末應收帳款";
table.Columns.Add(col);
}
private void InitDataGridView()
{
MutilGridHeader topRow = new MutilGridHeader();
topRow.SetRowCol(3, 18);
//第一行
topRow.Cells[0][0].Value = "客戶";
topRow.Cells[0][0].RowSpan = 3;
topRow.Cells[0][1].Value = "產品名稱";
topRow.Cells[0][1].RowSpan = 3;
topRow.Cells[0][2].Value = "規格";
topRow.Cells[0][2].RowSpan = 3;
topRow.Cells[0][3].Value = "單位";
topRow.Cells[0][3].RowSpan = 3;
topRow.Cells[0][4].Value = "期初";
topRow.Cells[0][4].ColSpan = 3;
topRow.Cells[0][7].Value = "本期";
topRow.Cells[0][7].ColSpan = 8;
topRow.Cells[0][15].Value = "期末";
topRow.Cells[0][15].ColSpan = 3;
//第二行
topRow.Cells[1][4].Value = "存貨數量";
topRow.Cells[1][4].RowSpan = 2;
topRow.Cells[1][5].Value = "應收貨款";
topRow.Cells[1][5].RowSpan = 2;
topRow.Cells[1][6].Value = "應收帳款";
topRow.Cells[1][6].RowSpan = 2;
topRow.Cells[1][7].Value = "發貨";
topRow.Cells[1][7].ColSpan = 2;
topRow.Cells[1][9].Value = "開票";
topRow.Cells[1][9].ColSpan = 2;
topRow.Cells[1][11].Value = "回款";
topRow.Cells[1][11].ColSpan = 2;
topRow.Cells[1][13].Value = "未開票回款";
topRow.Cells[1][13].ColSpan = 2;
topRow.Cells[1][15].Value = "存貨數量";
topRow.Cells[1][15].RowSpan = 2;
topRow.Cells[1][16].Value = "應收貨款";
topRow.Cells[1][16].RowSpan = 2;
topRow.Cells[1][17].Value = "應收票款";
topRow.Cells[1][17].RowSpan = 2;
//第三行
topRow.Cells[2][7].Value = "數量";
topRow.Cells[2][8].Value = "金額";
topRow.Cells[2][9].Value = "數量";
topRow.Cells[2][10].Value = "金額";
topRow.Cells[2][11].Value = "數量";
topRow.Cells[2][12].Value = "金額";
topRow.Cells[2][13].Value = "數量";
topRow.Cells[2][14].Value = "金額";
dataGridViewEx1.Header = topRow;
dataGridViewEx1.DataSource = table;
table.DefaultView.AllowNew = false;
dataGridViewEx1.Columns[0].Width = 120;
dataGridViewEx1.Columns[1].Width = 100;
dataGridViewEx1.Columns[2].Width = 80;
for(int i = 2;i<18;i++)
dataGridViewEx1.Columns[i].Width = 60;
}
4、界面顯示
這段代碼是兩年前寫的,由於當時時間和編程水平有限,很多代碼段沒有加注釋,代碼的可讀性極差,只是為了達到效果,具體合並的實現方法自己也已模糊。