using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Design;
using System.IO;
using System.Windows.Forms;
using System.Xml.Serialization;
namespace SGTool.Controls
{
// colum map : colum and RowPairDic
using ColumPairDic = Dictionary<int, Dictionary<int, int>>;
// rows map in a colum : startRow, endRow
using RowPairDic = Dictionary<int, int>;
public class HeaderInfo
{
public class HeaderCellBorderInfo
{
public bool Top;
public bool Left;
public bool Right;
public bool Bottom;
}
public HeaderInfo(int rowCount, int colCount, List<HeaderCellInfo> headerCellInfoList)
{
RowCount = rowCount;
ColCount = colCount;
HeaderCellInfoList = headerCellInfoList;
InitHeaderInfo();
}
private void InitHeaderInfo()
{
CellNames = new string[RowCount, ColCount];
CellBorders = new HeaderCellBorderInfo[RowCount, ColCount];
Alignments = new DataGridViewContentAlignment[RowCount, ColCount];
CellCrosses = new Rectangle[RowCount, ColCount];
for (int i = 0; i < RowCount; i++)
{
for (int j = 0; j < ColCount; j++)
{
CellNames[i, j] = string.Empty;
CellBorders[i, j] = new HeaderCellBorderInfo();
Alignments[i, j] = DataGridViewContentAlignment.MiddleCenter;
}
}
for (int i = 0; i < RowCount; i++)
{
CellBorders[i, 0].Left = true;
CellBorders[i, ColCount - 1].Right = true;
}
for (int j = 0; j < ColCount; j++)
{
CellBorders[0, j].Top = true;
CellBorders[RowCount - 1, j].Bottom = true;
}
foreach (HeaderCellInfo headerCellInfo in HeaderCellInfoList)
{
for (int i = headerCellInfo.Row; i < headerCellInfo.Row + headerCellInfo.RowSpan; i++)
{
for (int j = headerCellInfo.Col; j < headerCellInfo.Col + headerCellInfo.ColSpan; j++)
{
CellNames[i, j] = headerCellInfo.CellName;
Alignments[i, j] = headerCellInfo.Alignment;
CellCrosses[i, j].X = headerCellInfo.Col;
CellCrosses[i, j].Y = headerCellInfo.Row;
CellCrosses[i, j].Width = headerCellInfo.ColSpan;
CellCrosses[i, j].Height = headerCellInfo.RowSpan;
}
}
for (int i = headerCellInfo.Row; i < headerCellInfo.Row + headerCellInfo.RowSpan; i++)
{
CellBorders[i, headerCellInfo.Col + headerCellInfo.ColSpan - 1].Right = true;
}
for (int j = headerCellInfo.Col; j < headerCellInfo.Col + headerCellInfo.ColSpan; j++)
{
CellBorders[headerCellInfo.Row + headerCellInfo.RowSpan - 1, j].Bottom = true;
}
}
}
public int RowCount;
public int ColCount;
public string[,] CellNames;
public HeaderCellBorderInfo[,] CellBorders;
public DataGridViewContentAlignment[,] Alignments;
public Rectangle[,] CellCrosses;
public List<HeaderCellInfo> HeaderCellInfoList;
}
public class HeaderCellInfo
{
public HeaderCellInfo()
{
}
public HeaderCellInfo(int row, int col, string cellName)
{
Row = row;
Col = col;
CellName = cellName;
}
public HeaderCellInfo(int row, int col, int rowSpan, int colSpan, string cellName)
{
Row = row;
Col = col;
RowSpan = rowSpan;
ColSpan = colSpan;
CellName = cellName;
}
public HeaderCellInfo(int row, int col, string cellName, DataGridViewContentAlignment alignment)
{
Row = row;
Col = col;
CellName = cellName;
Alignment = alignment;
}
public HeaderCellInfo(int row, int col, int rowSpan, int colSpan, string cellName, DataGridViewContentAlignment alignment)
{
Row = row;
Col = col;
RowSpan = rowSpan;
ColSpan = colSpan;
CellName = cellName;
Alignment = alignment;
}
public int Row;
public int Col;
public int RowSpan = 1;
public int ColSpan = 1;
public string CellName = string.Empty;
public DataGridViewContentAlignment Alignment = DataGridViewContentAlignment.MiddleCenter;
}
public class HeaderSetting
{
private int _rowCount;
public int RowCount
{
get { return _rowCount; }
set { _rowCount = value; }
}
private int _colCount;
public int ColCount
{
get { return _colCount; }
set { _colCount = value; }
}
private List<HeaderCellInfo> _headerCellInfoList = new List<HeaderCellInfo>();
public List<HeaderCellInfo> HeaderCellInfoList
{
get { return _headerCellInfoList; }
set { _headerCellInfoList = value; }
}
}
public partial class DataGridViewCellMerge : DataGridView
{
public DataGridViewCellMerge()
{
InitializeComponent();
this.RowHeadersVisible = false;
//this.ColumnHeadersVisible = false;
this.AutoSizeRowsMode = DataGridViewAutoSizeRowsMode.AllCells;
this.AllowUserToAddRows = false;
this.MultiSelect = false;
this.SelectionMode = DataGridViewSelectionMode.RowHeaderSelect;
}
// merged rows with same value in a colum
private ColumPairDic columDic = new ColumPairDic();
// header info
private HeaderInfo _headerInfo;
// the rule of how to merge cell
public ColumPairDic MergedRule
{
set { columDic = value; }
}
// header info
public HeaderInfo HeaderInfo
{
set
{
_headerInfo = value;
}
}
private string _headerInfoString;
[Editor("System.ComponentModel.Design.MultilineStringEditor, System.Design, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", typeof(UITypeEditor))]
public string HeaderInfoString
{
get
{
return _headerInfoString;
}
set
{
_headerInfoString = value;
try
{
using (StringReader stringReader = new StringReader(_headerInfoString))
{
XmlSerializer xmlSerializer = new XmlSerializer(typeof(HeaderSetting));
HeaderSetting headerSetting = (HeaderSetting)xmlSerializer.Deserialize(stringReader);
if (headerSetting == null)
{
return;
}
HeaderInfo = new HeaderInfo(headerSetting.RowCount,
headerSetting.ColCount,
headerSetting.HeaderCellInfoList);
}
}
catch
{
}
}
}
protected override void OnCellPainting(DataGridViewCellPaintingEventArgs e)
{
try
{
if (e.RowIndex == -1)
{
PaintHeader(e);
}
else
{
PaintCell(e);
}
}
catch
{
}
base.OnCellPainting(e);
}
// add all the index of merged rows into a list
private List<int> GetMergedRows(RowPairDic rowDic)
{
List<int> rowList = new List<int>();
Dictionary<int, int>.KeyCollection keys = rowDic.Keys;
foreach (int key in keys)
{
int startRow = -1;
int endRow = -1;
startRow = key;
rowDic.TryGetValue(key, out endRow);
for (int row = startRow; row < endRow + 1; row++)
{
rowList.Add(row);
}
}
return rowList;
}
private void PaintCell(DataGridViewCellPaintingEventArgs e)
{
e.CellStyle.SelectionForeColor = e.CellStyle.ForeColor;
e.CellStyle.SelectionBackColor = e.CellStyle.BackColor;
bool normalCell = true;
if (columDic.ContainsKey(e.ColumnIndex))
{
// the colum contains some merged cells
RowPairDic rowDic = new RowPairDic();
columDic.TryGetValue(e.ColumnIndex, out rowDic);
if (rowDic.Count != 0)
{
// get all the merged row in a colum
List<int> rowList = GetMergedRows(rowDic);
if (rowList.Contains(e.RowIndex))
{
normalCell = false;
e.PaintBackground(e.ClipBounds, false);
// the cell is the first row of the merged cells
if (rowDic.ContainsKey(e.RowIndex))
{
// paint the info
e.PaintContent(e.ClipBounds);
}
// the cell is a merged cell
if (rowDic.ContainsValue(e.RowIndex))
{
// the cell is the end row of the merged cells
// draw the line under the cell
e.Graphics.DrawLine(new Pen(this.GridColor), e.CellBounds.Left, e.CellBounds.Bottom - 1,
e.CellBounds.Right - 1, e.CellBounds.Bottom - 1);
}
else
{
// the cell is NOT the end row of the merged cells
// clear the line under the cell
e.Graphics.DrawLine(new Pen(e.CellStyle.BackColor), e.CellBounds.Left, e.CellBounds.Bottom - 1,
e.CellBounds.Right - 2, e.CellBounds.Bottom - 1);
}
}
}// end of if (rowDic.Count != 0)
} // end of if (columDic.ContainsKey(e.ColumnIndex))
if (normalCell)
{
e.PaintBackground(e.ClipBounds, false);
e.PaintContent(e.ClipBounds);
}
e.Handled = true;
}// e
private void PaintHeader(DataGridViewCellPaintingEventArgs e)
{
// head line
if (_headerInfo == null)
{
return;
}
int[] rowTops = new int[_headerInfo.RowCount];
int[] rowBottoms = new int[_headerInfo.RowCount];
rowTops[0] = e.CellBounds.Top;
for (int i = 1; i < _headerInfo.RowCount; i++)
{
rowTops[i] = e.CellBounds.Height * i / _headerInfo.RowCount + rowTops[0];
}
rowBottoms[_headerInfo.RowCount - 1] = e.CellBounds.Bottom;
for (int i = 0; i < _headerInfo.RowCount - 1; i++)
{
rowBottoms[i] = rowTops[i + 1];
}
for (int i = 0; i < _headerInfo.RowCount; i++)
{
PaintHeaderCellBackground(
e,
_headerInfo.CellBorders[i, e.ColumnIndex],
e.CellBounds.Left,
rowTops[i],
e.CellBounds.Right,
rowBottoms[i]);
}
for (int i = 0; i < _headerInfo.RowCount; i++)
{
Rectangle cross = _headerInfo.CellCrosses[i, e.ColumnIndex];
int x2 = e.CellBounds.Left;
if (x2 < 2)
{
x2++;
}
int w2=0;
for (int col = cross.X; col < cross.Width + cross.X;col ++)
{
w2 += this.Columns[col].Width;
if (col < e.ColumnIndex)
{
x2 -= this.Columns[col].Width;
}
}
//int x = this.GetCellDisplayRectangle(cross.X, -1, true).X;
int y = rowTops[cross.Y];
//int width = this.GetCellDisplayRectangle(cross.X + cross.Width - 1, -1, true).X +
// this.GetCellDisplayRectangle(cross.X + cross.Width - 1, -1, true).Width - x;
int height = rowBottoms[cross.Y + cross.Height - 1] - y;
PaintHeaderCellContent(
e,
_headerInfo.CellNames[i, e.ColumnIndex],
x2,//x,
y,
w2,//width,
height,
_headerInfo.Alignments[i, e.ColumnIndex]);
}
e.Handled = true;
}
private void PaintHeaderCellBackground(DataGridViewCellPaintingEventArgs e, HeaderInfo.HeaderCellBorderInfo border, int left, int top, int right, int bottom)
{
Brush brushBack = new SolidBrush(this.ColumnHeadersDefaultCellStyle.BackColor);
e.Graphics.FillRectangle(brushBack, left, top, right - left, bottom - top);
right--;
bottom--;
Pen penGrid = new Pen(this.GridColor);
if (border.Top)
{
e.Graphics.DrawLine(penGrid, left, top, right, top);
}
if (border.Left)
{
e.Graphics.DrawLine(penGrid, left, top, left, bottom);
}
if (border.Right)
{
e.Graphics.DrawLine(penGrid, right, top, right, bottom);
}
if (border.Bottom)
{
e.Graphics.DrawLine(penGrid, left, bottom, right, bottom);
}
}
private void PaintHeaderCellContent(DataGridViewCellPaintingEventArgs e,
string colName,
int x, int y, int width, int height,
DataGridViewContentAlignment alignment)
{
StringFormat drawFormat = new StringFormat();
drawFormat.Alignment = StringAlignment.Center;
drawFormat.LineAlignment = StringAlignment.Center;
if (alignment == DataGridViewContentAlignment.MiddleLeft)
{
drawFormat.Alignment = StringAlignment.Near;
}
e.Graphics.DrawString(colName,
this.Font,
new SolidBrush(e.CellStyle.ForeColor),
new RectangleF(x, y, width, height), drawFormat);
//e.Graphics.DrawRectangle(Pens.Red, x, y, width, height);
//e.Graphics.DrawRectangle(Pens.Yellow, x + 1, y + 1, width - 2, height - 2);
}
/// <summary>
/// Unite Cells
/// </summary>
/// <param name="startRow"> start row index </param>
/// <param name="endRow"> end row index </param>
/// <param name="endCol"> columnIndex </param>
public void UniteCells(int startRow, int endRow, int columnIndex)
{
RowPairDic rowPairDic = new RowPairDic();
if (startRow > endRow)
{
return;
}
rowPairDic.Add(startRow, endRow);
columDic.Add(columnIndex, rowPairDic);
}
}// end of class
}// end of names