借鉴别人的,改了改,没用timer

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Drawing.Design;

namespace Salem.Library.Control.DataGridView
{
/// <summary>
/// 拥有默认样式带合并表头功能的DataGridView
/// </summary>
public partial class DataGridViewEx : System.Windows.Forms.DataGridView
{
#region 字段属性

//是否显示行号
private bool showNum = false;
/// <summary>
/// 是否显示行号
/// </summary>
[DefaultValue(true), Description("是否显示行号")]
public bool ShowNum
{
get
{
return showNum;
}
set
{
showNum = value;
if (value)
{
this.RowHeadersVisible = true;
}
}
}

private Dictionary<int, SpanInfo> SpanRows = new Dictionary<int, SpanInfo>();

private List<string> _mergecolumnname = new List<string>();
/// <summary>
/// 合并列的名称
/// </summary>
[MergableProperty(false), Editor("System.Windows.Forms.Design.ListControlStringCollectionEditor, System.Design, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", typeof(UITypeEditor)), DesignerSerializationVisibility(DesignerSerializationVisibility.Visible), Localizable(true), Description("设置或获取合并列的集合"), Browsable(true), Category("单元格合并")]
public List<string> MergeColumnNames
{
get
{
return this._mergecolumnname;
}
set
{
this._mergecolumnname = value;
}
}

#endregion

#region 构造函数
public DataGridViewEx()
{
SetProperty();
SetStyle(
ControlStyles.AllPaintingInWmPaint |
ControlStyles.OptimizedDoubleBuffer |
ControlStyles.ResizeRedraw |
ControlStyles.DoubleBuffer, true);
InitializeComponent();

}
#endregion

#region 样式设置方法
//设置样式属性
private void SetProperty()
{
this.AutoGenerateColumns = false;
this.BackgroundColor = Color.White;
//设置奇数行单元格的样式
this.AlternatingRowsDefaultCellStyle = CreatAlternatingCellStyle();
//设置默认单元格的样式
this.DefaultCellStyle = CreatDefaultCellStyle();
this.ColumnHeadersDefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleCenter;
this.ColumnHeadersDefaultCellStyle.BackColor = Color.FromArgb(247, 247, 247);
this.ColumnHeadersDefaultCellStyle.Font = new Font("宋体", 10);
//this.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill;
this.CellBorderStyle = DataGridViewCellBorderStyle.SunkenHorizontal;
this.ColumnHeadersBorderStyle = DataGridViewHeaderBorderStyle.None;
this.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.EnableResizing;
this.ColumnHeadersHeight = 35;
this.EnableHeadersVisualStyles = false;
this.RowHeadersBorderStyle = DataGridViewHeaderBorderStyle.None;
this.RowHeadersVisible = false;
this.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
this.RowTemplate.Height = 35;
}

//设置奇数行的样式
private DataGridViewCellStyle CreatAlternatingCellStyle()
{
DataGridViewCellStyle alternatingRowStyle = new DataGridViewCellStyle();
alternatingRowStyle.Font = new System.Drawing.Font("宋体", 10);
//alternatingRowStyle.Alignment = DataGridViewContentAlignment.MiddleCenter;
alternatingRowStyle.BackColor = Color.White;
alternatingRowStyle.ForeColor = Color.Black;
alternatingRowStyle.SelectionBackColor = Color.FromArgb(255, 230, 162);
alternatingRowStyle.SelectionForeColor = Color.Black;
return alternatingRowStyle;
}

//设置默认单元格的样式
private DataGridViewCellStyle CreatDefaultCellStyle()
{
DataGridViewCellStyle defaultCellStyle = new DataGridViewCellStyle();
//defaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleCenter;
defaultCellStyle.Font = new System.Drawing.Font("宋体", 10);
defaultCellStyle.BackColor = Color.White;
defaultCellStyle.ForeColor = Color.Black;
defaultCellStyle.SelectionBackColor = Color.FromArgb(255, 230, 162);
defaultCellStyle.SelectionForeColor = Color.Black;
return defaultCellStyle;
}

/// <summary>
/// 设置单元格和列头有边框
/// </summary>
public void SetGirdCellAndColHeaderBorderStyle()
{
this.CellBorderStyle = DataGridViewCellBorderStyle.Single;
this.ColumnHeadersBorderStyle = DataGridViewHeaderBorderStyle.Single;
}
#endregion

#region 重绘方法

protected override void OnPaint(PaintEventArgs pe)
{
base.OnPaint(pe);
}

protected override void OnCellPainting(DataGridViewCellPaintingEventArgs e)
{
try
{
if (e.RowIndex > -1 && e.ColumnIndex > -1)
{
//DrawCell(e);
}
else
{
//合并表头
if (e.RowIndex == -1)
{
if (SpanRows.ContainsKey(e.ColumnIndex)) //被合并的列
{
//画边框
Graphics g = e.Graphics;
e.Paint(e.CellBounds, DataGridViewPaintParts.Background | DataGridViewPaintParts.Border);

int left = e.CellBounds.Left, top = e.CellBounds.Top + 2,
right = e.CellBounds.Right, bottom = e.CellBounds.Bottom;

switch (SpanRows[e.ColumnIndex].Position)
{
case 1:
left += 2;
break;
case 2:
break;
case 3:
right -= 2;
break;
}

//画底色
g.FillRectangle(new SolidBrush(e.CellStyle.BackColor), left, top,
right - left, (bottom - top)/2);

//画中线
g.DrawLine(new Pen(this.GridColor), left-2, (top + bottom) / 2,
right, (top + bottom) / 2);

//写合并标题
StringFormat _sf = new StringFormat { Alignment = StringAlignment.Center, LineAlignment = StringAlignment.Center };

g.DrawString(e.Value + "", e.CellStyle.Font, Brushes.Black,
new Rectangle(left, (top + bottom) / 2, right - left, (bottom - top) / 2), _sf);

//写原来列标题
StringFormat sf = new StringFormat();
sf.Alignment = StringAlignment.Center;
sf.LineAlignment = StringAlignment.Center;

left = this.GetColumnDisplayRectangle(SpanRows[e.ColumnIndex].Left, true).Left - 2;
if (left < 0) left = this.GetCellDisplayRectangle(-1, -1, true).Width;
right = this.GetColumnDisplayRectangle(SpanRows[e.ColumnIndex].Right, true).Right - 2;
if (right < 0) right = this.Width;
g.DrawString(SpanRows[e.ColumnIndex].Text, this.ColumnHeadersDefaultCellStyle.Font, new SolidBrush(e.CellStyle.ForeColor),
new Rectangle(left, top, right - left, (bottom - top)/2), sf);
e.Handled = true;
}
}
}
base.OnCellPainting(e);
}
catch
{ }
}

//绘制行号
protected override void OnRowPostPaint(DataGridViewRowPostPaintEventArgs e)
{
if (ShowNum)
{
this.RowHeadersVisible = true;
SolidBrush solidBrush = new SolidBrush(Color.Black);
e.Graphics.DrawString((e.RowIndex + 1).ToString(), e.InheritedRowStyle.Font, solidBrush, e.RowBounds.Location.X + 15, e.RowBounds.Location.Y + 5);
}
base.OnRowPostPaint(e);
}

//重绘滚动条
protected override void OnScroll(ScrollEventArgs e)
{
this.ReDrawHead();
base.OnScroll(e);
}

//重绘标题行
public void ReDrawHead()
{
foreach (int num in this.SpanRows.Keys)
{
base.Invalidate(base.GetCellDisplayRectangle(num, -1, true));
}
}

#endregion

#region 自定义方法
/// <summary>
/// 画单元格
/// </summary>
/// <param name="e"></param>
private void DrawCell(DataGridViewCellPaintingEventArgs e)
{
if (e.CellStyle.Alignment == DataGridViewContentAlignment.NotSet)
{
e.CellStyle.Alignment = DataGridViewContentAlignment.MiddleCenter;
}
Brush gridBrush = new SolidBrush(this.GridColor);
SolidBrush backBrush = new SolidBrush(e.CellStyle.BackColor);
SolidBrush fontBrush = new SolidBrush(e.CellStyle.ForeColor);
int cellwidth;
//上面相同的行数
int UpRows = 0;
//下面相同的行数
int DownRows = 0;
//总行数
int count = 0;
if (this.MergeColumnNames.Contains(this.Columns[e.ColumnIndex].Name) && e.RowIndex != -1)
{
cellwidth = e.CellBounds.Width;
Pen gridLinePen = new Pen(gridBrush);
string curValue = e.Value == null ? "" : e.Value.ToString().Trim();
string curSelected = this.CurrentRow.Cells[e.ColumnIndex].Value == null ? "" : this.CurrentRow.Cells[e.ColumnIndex].Value.ToString().Trim();
if (!string.IsNullOrEmpty(curValue))
{
#region 获取下面的行数
for (int i = e.RowIndex; i < this.Rows.Count; i++)
{
if (this.Rows[i].Cells[e.ColumnIndex].Value.ToString().Equals(curValue))
{
//this.Rows[i].Cells[e.ColumnIndex].Selected = this.Rows[e.RowIndex].Cells[e.ColumnIndex].Selected;
if (!this.Rows[i].Cells[0].Value.ToString().Equals(this.Rows[e.RowIndex].Cells[0].Value.ToString()))
break;
DownRows++;
if (e.RowIndex != i)
{
cellwidth = cellwidth < this.Rows[i].Cells[e.ColumnIndex].Size.Width ? cellwidth : this.Rows[i].Cells[e.ColumnIndex].Size.Width;
}
}
else
{
break;
}
}
#endregion
#region 获取上面的行数
for (int i = e.RowIndex; i >= 0; i--)
{
if (this.Rows[i].Cells[e.ColumnIndex].Value.ToString().Equals(curValue))
{
if (!this.Rows[e.RowIndex].Cells[0].Value.ToString().Equals(this.Rows[i].Cells[0].Value.ToString()))
{
break;
}
//this.Rows[i].Cells[e.ColumnIndex].Selected = this.Rows[e.RowIndex].Cells[e.ColumnIndex].Selected;
UpRows++;
if (e.RowIndex != i)
{
cellwidth = cellwidth < this.Rows[i].Cells[e.ColumnIndex].Size.Width ? cellwidth : this.Rows[i].Cells[e.ColumnIndex].Size.Width;
}
}
else
{
break;
}
}
#endregion
count = DownRows + UpRows - 1;
if (count < 2)
{
return;
}
}
if (this.Rows[e.RowIndex].Selected)
{
backBrush.Color = e.CellStyle.SelectionBackColor;
fontBrush.Color = e.CellStyle.SelectionForeColor;
}
//以背景色填充
e.Graphics.FillRectangle(backBrush, e.CellBounds);
//画字符串
PaintingFont(e, cellwidth, UpRows, DownRows, count);
if (DownRows == 1)
{
e.Graphics.DrawLine(gridLinePen, e.CellBounds.Left, e.CellBounds.Bottom - 1, e.CellBounds.Right - 1, e.CellBounds.Bottom - 1);
count = 0;
}
// 画右边线
e.Graphics.DrawLine(gridLinePen, e.CellBounds.Right - 1, e.CellBounds.Top, e.CellBounds.Right - 1, e.CellBounds.Bottom);

e.Handled = true;
}
}
/// <summary>
/// 画字符串
/// </summary>
/// <param name="e"></param>
/// <param name="cellwidth"></param>
/// <param name="UpRows"></param>
/// <param name="DownRows"></param>
/// <param name="count"></param>
private void PaintingFont(System.Windows.Forms.DataGridViewCellPaintingEventArgs e, int cellwidth, int UpRows, int DownRows, int count)
{
SolidBrush fontBrush = new SolidBrush(e.CellStyle.ForeColor);
int fontheight = (int)e.Graphics.MeasureString(e.Value.ToString(), e.CellStyle.Font).Height;
int fontwidth = (int)e.Graphics.MeasureString(e.Value.ToString(), e.CellStyle.Font).Width;
int cellheight = e.CellBounds.Height;

if (e.CellStyle.Alignment == DataGridViewContentAlignment.BottomCenter)
{
e.Graphics.DrawString((String)e.Value, e.CellStyle.Font, fontBrush, e.CellBounds.X + (cellwidth - fontwidth) / 2, e.CellBounds.Y + cellheight * DownRows - fontheight);
}
else if (e.CellStyle.Alignment == DataGridViewContentAlignment.BottomLeft)
{
e.Graphics.DrawString((String)e.Value, e.CellStyle.Font, fontBrush, e.CellBounds.X, e.CellBounds.Y + cellheight * DownRows - fontheight);
}
else if (e.CellStyle.Alignment == DataGridViewContentAlignment.BottomRight)
{
e.Graphics.DrawString((String)e.Value, e.CellStyle.Font, fontBrush, e.CellBounds.X + cellwidth - fontwidth, e.CellBounds.Y + cellheight * DownRows - fontheight);
}
else if (e.CellStyle.Alignment == DataGridViewContentAlignment.MiddleCenter)
{
e.Graphics.DrawString((String)e.Value, e.CellStyle.Font, fontBrush, e.CellBounds.X + (cellwidth - fontwidth) / 2, e.CellBounds.Y - cellheight * (UpRows - 1) + (cellheight * count - fontheight) / 2);
}
else if (e.CellStyle.Alignment == DataGridViewContentAlignment.MiddleLeft)
{
e.Graphics.DrawString((String)e.Value, e.CellStyle.Font, fontBrush, e.CellBounds.X, e.CellBounds.Y - cellheight * (UpRows - 1) + (cellheight * count - fontheight) / 2);
}
else if (e.CellStyle.Alignment == DataGridViewContentAlignment.MiddleRight)
{
e.Graphics.DrawString((String)e.Value, e.CellStyle.Font, fontBrush, e.CellBounds.X + cellwidth - fontwidth, e.CellBounds.Y - cellheight * (UpRows - 1) + (cellheight * count - fontheight) / 2);
}
else if (e.CellStyle.Alignment == DataGridViewContentAlignment.TopCenter)
{
e.Graphics.DrawString((String)e.Value, e.CellStyle.Font, fontBrush, e.CellBounds.X + (cellwidth - fontwidth) / 2, e.CellBounds.Y - cellheight * (UpRows - 1));
}
else if (e.CellStyle.Alignment == DataGridViewContentAlignment.TopLeft)
{
e.Graphics.DrawString((String)e.Value, e.CellStyle.Font, fontBrush, e.CellBounds.X, e.CellBounds.Y - cellheight * (UpRows - 1));
}
else if (e.CellStyle.Alignment == DataGridViewContentAlignment.TopRight)
{
e.Graphics.DrawString((String)e.Value, e.CellStyle.Font, fontBrush, e.CellBounds.X + cellwidth - fontwidth, e.CellBounds.Y - cellheight * (UpRows - 1));
}
else
{
e.Graphics.DrawString((String)e.Value, e.CellStyle.Font, fontBrush, e.CellBounds.X + (cellwidth - fontwidth) / 2, e.CellBounds.Y - cellheight * (UpRows - 1) + (cellheight * count - fontheight) / 2);
}
}

#endregion

#region 合并表头方法

/// <summary>
/// 合并列
/// </summary>
/// <param name="ColIndex">列的索引</param>
/// <param name="ColCount">需要合并的列数</param>
/// <param name="Text">合并列后的文本</param>
public void AddSpanHeader(int ColIndex, int ColCount, string Text)
{
if (ColCount < 2)
{
//throw new Exception("行宽应大于等于2,合并1列无意义。");
}
//将这些列加入列表
int Right = ColIndex + ColCount - 1; //同一大标题下的最后一列的索引
SpanRows[ColIndex] = new SpanInfo(Text, 1, ColIndex, Right); //添加标题下的最左列
SpanRows[Right] = new SpanInfo(Text, 3, ColIndex, Right); //添加该标题下的最右列
for (int i = ColIndex + 1; i < Right; i++) //中间的列
{
SpanRows[i] = new SpanInfo(Text, 2, ColIndex, Right);
}
}

/// <summary>
/// 清除合并表头
/// </summary>
public void ClearSpanInfo()
{
this.SpanRows.Clear();
}

#endregion

#region 获取绑定数据
/// <summary>
/// 获取显示列绑定数据
/// </summary>
/// <returns></returns>
public DataTable GetVisibleBoundData()
{
DataTable dt = new DataTable();
foreach (DataGridViewColumn dgvc in this.Columns)
{
if (!dgvc.Visible || string.IsNullOrEmpty(dgvc.HeaderText))
{
continue;
}
if (dgvc is DataGridViewTextBoxColumn || dgvc is DataGridViewComboBoxColumn || dgvc is DataGridViewLinkColumn)
{
if (!dt.Columns.Contains(dgvc.HeaderText) && dgvc.HeaderText.Length > 0)
{
if (dgvc.ValueType == null)
{
dt.Columns.Add(dgvc.HeaderText);
}
else
{
dt.Columns.Add(dgvc.HeaderText, dgvc.ValueType);
}
}
}
}

foreach (DataGridViewRow dgvr in this.Rows)
{
if (dgvr.IsNewRow)
{
continue;
}
if (string.IsNullOrEmpty(dgvr.Cells[1].Value != null ? dgvr.Cells[1].Value.ToString() : ""))
{
continue;
}
DataRow dr = dt.NewRow();
foreach (DataGridViewColumn dgvc in this.Columns)
{
if (dt.Columns.Contains(dgvc.HeaderText))
{
if (dgvr.Cells[dgvc.Name].FormattedValue.ToString().Length > 0)
{
dr[dgvc.HeaderText] = dgvr.Cells[dgvc.Name].FormattedValue;
}
}
}
dt.Rows.Add(dr);
}

return dt;
}
#endregion

}

[StructLayout(LayoutKind.Sequential)]
public struct SpanInfo
{
/// <summary>
/// 合并后的标题
/// </summary>
public string Text;
/// <summary>
/// 本身位置(是左边界列还是有边界列)
/// </summary>
public int Position;
/// <summary>
/// 左边界列
/// </summary>
public int Left;
/// <summary>
/// 右边界列
/// </summary>
public int Right;
public SpanInfo(string Text, int Position, int Left, int Right)
{
this.Text = Text;
this.Position = Position;
this.Left = Left;
this.Right = Right;
}
}
}

使用:

DataTable dt = new DataTable();

     dt.Columns.Add("1");
     dt.Columns.Add("2");
     dt.Columns.Add("3");
     dt.Columns.Add("4");
     dt.Rows.Add("中国", "上海", "5000", "7000");
     dt.Rows.Add("中国", "北京", "3000", "5600");
     dt.Rows.Add("美国", "纽约", "6000", "8600");
     dt.Rows.Add("美国", "华劢顿", "8000", "9000");
     dt.Rows.Add("英国", "伦敦", "7000", "8800");
     this.rowMergeView1.DataSource = dt;
     this.rowMergeView1.ColumnHeadersHeight = 40;
     this.rowMergeView1.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.DisableResizing;
     //this.rowMergeView1.MergeColumnNames.Add("Column1");
     this.rowMergeView1.AddSpanHeader(2, 2, "XXXX");

Datagridview 实现二维表头和行合并的更多相关文章

  1. Datagridview 实现二维表头和行合并【转载】

    using System; using System.Collections.Generic; using System.ComponentModel; using System.Drawing; u ...

  2. 如何通过DataGridView 实现单元格合并和二维表头

    先看下实现出来的效果(这里随便写了几组数据,用来测试) 先初始一个DataGridView 设置哪几列 DataGridView 里男女这两列的 AutoSizeMode 可以设置Fill. publ ...

  3. 【Winform-自定义控件】DataGridView 单元格合并和二维表头

    DataGridView单元格合并和二维表头应用: //DataGridView绑定数据 DataTable dt = new DataTable(); dt.Columns.Add("); ...

  4. PyTorch 如何理解张量:一维张量、二维张量、行/列向量、矩阵

    理解张量,并将张量与线性代数的知识连接起来,我认为最重要的是理解 tensor 的两个属性:shape 和 ndim . ndim 表示张量的维度,一维张量的 ndim 值为 1,二维张量的 ndim ...

  5. C#获取二维数组的行数和列数及其多维。。。

    原文发布时间为:2008-11-26 -- 来源于本人的百度文章 [由搬家工具导入] 有一个二维数组sz[,] 怎样获取sz 的行数和列数呢? sz.GetLength(0) 返回第一维的长度(即行数 ...

  6. (转)DataGridView多维表头及其扩展功能

    dataGridView1.RowHeadersVisible = false;把整行选中那一列去掉.如果需要整行选中,新增一按钮列模拟实现.上源码:多维DataGridView 有个简易的方法: 1 ...

  7. C#中如何获取一个二维数组的两维长度,即行数和列数?以及多维数组各个维度的长度?

    如何获取二维数组中的元素个数呢? int[,] array = new int[,] {{1,2,3},{4,5,6},{7,8,9}};//定义一个3行3列的二维数组int row = array. ...

  8. C#中Winform程序中如何实现多维表头【不通过第三方报表程序】

    问题:C#中Winform程序中如何实现多维表头. 在网上搜了很多方法,大多数方法对于我这种新手,看的都不是很懂.最后在新浪博客看到了一篇比较易懂的文章:[DataGridView二维表头与合并单元格 ...

  9. 扫二维码下载apk并统计被扫描次数(及微信屏蔽下载解决方案)

    转载请注明出处:http://www.cnblogs.com/Joanna-Yan/p/5395715.html 需求:想让用户扫描一个二维码就能下载APP,并统计被扫描次数. 两种实现方法: 1.一 ...

随机推荐

  1. trove database功能总结

    我曾经以为trove只负责数据库(datastore)的部署,最近才发现trove可以进行数据库(database)的创建. 首先是列出某个实例上(instance)数据库(datastrore)上的 ...

  2. 字符串处理 - ANSI - Unicode - UTF8 转换

    #include <stdio.h> #include <windows.h> #include <locale.h> #define BUFF_SIZE 1024 ...

  3. JavaScript之基于原型链的继承

    本文介绍下js的OOP中的继承. 上图的要点为:Foo函数在创建时会自动生成内置属性prototype,而typeof Foo.prototype是object类型的. 上图的要点为:Foo.prot ...

  4. 小程序使用wxs 解决wxml保留2位小数问题

    1.出现溢出表现 从图中可以看到数字超出了很长长度.代码里面是如下这样的.为什么在0.35出现?或者一些相成的计算出现? 而 0.34却不会. 0.41 也会出现,好像是二进制运算出现结果. data ...

  5. UVA 11468 AC 自动机

    首先我们应该是枚举 L个位置上的每个字符来得到最终概率 然后AC自动机的作用就是为了判断你枚举的地方是否对应了单词节点,如果对应了,就肯定要不得 #include <iostream> # ...

  6. 题解【[CQOI2017]小Q的棋盘】

    切了水题十分快乐~ 首先发现本题结构一定是颗树~ 本题样例1: ..没啥用? 样例2: 这个时候我们发现:根据贪心思想我们希望每次走一步都多走一个点,如果我们选择最长链的话,在链上每走一步就多走了一个 ...

  7. 美团:WSDM Cup 2019自然语言推理任务获奖解题思路

    WSDM(Web Search and Data Mining,读音为Wisdom)是业界公认的高质量学术会议,注重前沿技术在工业界的落地应用,与SIGIR一起被称为信息检索领域的Top2. 刚刚在墨 ...

  8. Python内置文件

    概述 为了提升效率,Python有些内置文件如 __pycache__.py 详解 1)__pycache__.py, python程序运行时不需要编译成二进制代码,而直接从源码运行程序 Python ...

  9. MQL4编程—值传递和引用传递

    定义 简单的说就是给一个变量或者对象取一个别名(引用和被引用的共享存储单元,要用修饰符&). 引用的用法 在MQL4中通过调试只接受引用作为函数参数的用法,在函数参数传递过程中,有两种传递方式 ...

  10. VC调用VB写的COM

    VB. 步骤: 1.创建类库:类库的创建必须分为接口和实现类:给外面提供的是COM接口: 创建了接口和类之后还要创建"Guid",这个在"工具->创建GUID&qu ...