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