背景

今天在做系统报表的过程中,我想实现批量操作DataGridView中的数据,在列中加复选框,通过一个事件触发进行全选或取消,可是在外面添加按钮,这种模式虽然能够实现,但是从系统界面设计的角度,美观和灵活性就差很多了,能否在DataGridView头标题栏上呈现复选框,通过这个头标题复选框来对这一列的复选框,这样是不是更灵活,也美观一点?

问题

可是,找了半天,发现微软原始的DataGridView头标题栏没有CheckBox的功能,郁闷了~~

我在伍兄的博客找到有关于扩展DataGridVew在头标题栏添加全选功能按钮的功能(不是源码开源),而且他的这个程序集也不能满足我的需求,怎么办?

只有靠我自已去探索了,我在传统的DataGridView中实现了这个功能,但是整合进我的换肤组件中不能实现,Why? 我找了好友Strong一起研究,自已摸不清方向,最后还是他找到了问题点,可是却无法入手?(no any solution)

最后,经过自已的努力一步一步debug, 终于解决了问题,并整合进自已的换肤组件中,个人觉得有必要总结一下。

在总结技术点前,先展示一下我的成果,然后再做扩展说明,如下:

(图一)Office2007Blue效果

(图二) Office2007Silver效果

传统的解决方案

在传统的DataGridView上,实现基本上没有什么难处,只要按如下的步骤去操作就可以了。

添加一个DataGridViewColumnHeaderCellW.cs,继承DataGridViewColumnHeaderCell,

源码如下:

public class DataGridViewColumnHeaderCellW : DataGridViewColumnHeaderCell
{
public object HeaderTextDataSource { get; set; }
private Type _dataSourceType = null;
public Type DataSourceType
{
get
{
if (HeaderTextDataSource != null && _dataSourceType == null)
_dataSourceType = HeaderTextDataSource.GetType();
return _dataSourceType;
}
set { _dataSourceType = value; }
}
public string FieldName { get; set; }
public string Prefix { get; set; }
public string Suffix { get; set; } Point checkBoxLocation;
Size checkBoxSize;
bool _checked = false;
Point _cellLocation = new Point();
System.Windows.Forms.VisualStyles.CheckBoxState _cbState =
System.Windows.Forms.VisualStyles.CheckBoxState.UncheckedNormal;
public event datagridviewcheckboxHeaderEventHander OnCheckBoxClicked;
//绘制列头checkbox
protected override void Paint(System.Drawing.Graphics graphics,
System.Drawing.Rectangle clipBounds,
System.Drawing.Rectangle cellBounds,
int rowIndex,
DataGridViewElementStates dataGridViewElementState,
object value,
object formattedValue,
string errorText,
DataGridViewCellStyle cellStyle,
DataGridViewAdvancedBorderStyle advancedBorderStyle,
DataGridViewPaintParts paintParts)
{
base.Paint(graphics, clipBounds, cellBounds, rowIndex,
dataGridViewElementState, value,
formattedValue, errorText, cellStyle,
advancedBorderStyle, paintParts);
Point p = new Point();
Size s = CheckBoxRenderer.GetGlyphSize(graphics,
System.Windows.Forms.VisualStyles.CheckBoxState.UncheckedNormal);
p.X = cellBounds.Location.X +
(cellBounds.Width / ) - (s.Width / ) - ; //列头checkbox的X坐标
p.Y = cellBounds.Location.Y +
(cellBounds.Height / ) - (s.Height / ); //列头checkbox的Y坐标
_cellLocation = cellBounds.Location;
checkBoxLocation = p;
checkBoxSize = s;
if (_checked)
_cbState = System.Windows.Forms.VisualStyles.
CheckBoxState.CheckedNormal;
else
_cbState = System.Windows.Forms.VisualStyles.
CheckBoxState.UncheckedNormal;
CheckBoxRenderer.DrawCheckBox
(graphics, checkBoxLocation, _cbState);
} /// <summary>
/// 点击列头checkbox单击事件
/// </summary>
protected override void OnMouseClick(DataGridViewCellMouseEventArgs e)
{ Point p = new Point(e.X + _cellLocation.X, e.Y + _cellLocation.Y);
if (p.X >= checkBoxLocation.X && p.X <=
checkBoxLocation.X + checkBoxSize.Width
&& p.Y >= checkBoxLocation.Y && p.Y <=
checkBoxLocation.Y + checkBoxSize.Height)
{
_checked = !_checked; //获取列头checkbox的选择状态
datagridviewCheckboxHeaderEventArgs ex = new datagridviewCheckboxHeaderEventArgs();
ex.CheckedState = _checked; object sender = new object();//此处不代表选择的列头checkbox,只是作为参数传递。应该列头checkbox是绘制出来的,无法获得它的实例 if (OnCheckBoxClicked != null)
{
OnCheckBoxClicked(sender, ex);//触发单击事件
this.DataGridView.InvalidateCell(this); } }
base.OnMouseClick(e);
}

在DataGridViewColumnHeaderCellW.cs内部,添加一个委托和继承EventArgs事件数据的基类:

public delegate void datagridviewcheckboxHeaderEventHander(object sender, datagridviewCheckboxHeaderEventArgs e);

    //定义包含列头checkbox选择状态的参数类
public class datagridviewCheckboxHeaderEventArgs : EventArgs
{
private bool checkedState = false; public bool CheckedState
{
get { return checkedState; }
set { checkedState = value; }
}
}

如何调用?

先在界面上添加一个DataGridView,并添加一列,选类型为DataGridViewCheckBoxColumn,在Form_Load事件中添加如下代码:

private void Form1_Load(object sender, EventArgs e)
{
DataGridViewColumnHeaderCellW ch = new DataGridViewColumnHeaderCellW();
ch.OnCheckBoxClicked += new datagridviewcheckboxHeaderEventHander(OnCheckBoxClicked);
//第三列为DataGridViewCheckBoxColumn
DataGridViewCheckBoxColumn checkboxCol = this.dataGridView1.Columns[] as DataGridViewCheckBoxColumn;
checkboxCol.HeaderCell = ch;
checkboxCol.HeaderCell.Value = string.Empty;//消除列头checkbox旁出现的文字
}

没题解决了!

展示一下,这个复选框暂放在最后一列,如下图:

这个真是灰头土脸,像是灰姑娘那么丑。

于是,我整合进我的换肤中,可是怎么也不能实现,标题栏就是不出来,结果成了如下图这样子:

最后经过一系列努力,定位问题在CellPainting事件中,重绘的过程把标题栏的checkbox效果覆盖了。

我在此事件中添加如下代码:

if (e.RowIndex == -)
{
if (!(_columnHeaderUpColor == Color.Transparent) && !(_columnHeaderDownColor == Color.Transparent) &&
!_columnHeaderUpColor.IsEmpty && !_columnHeaderDownColor.IsEmpty)
{
DrawLinearGradient(e.CellBounds, e.Graphics, _columnHeaderUpColor, _columnHeaderDownColor);
if (ShowColumnHeaderCheckBox)
{
e.Paint(e.ClipBounds, (DataGridViewPaintParts.All & ~DataGridViewPaintParts.Background));
}
else
{
DrawText(e);
}
e.Handled = true;
}
}

问题终于解决,但是在代码中为什么用ShowColumnHeaderCheckBox?

并不是所有的数据呈现功能都要有这个头标题栏复选框的功能,为了更好的兼容性,我在添加了这个属性,开发人员可以通过此属性灵活选择,默认是false。

public bool showColumnHeaderCheckBox;

        public bool ShowColumnHeaderCheckBox
{
get
{
return showColumnHeaderCheckBox;
}
set { showColumnHeaderCheckBox = value; }
}

在客户端这样去设就可以了。

private void Form1_Load(object sender, EventArgs e)
{
InitParameterList();
dataGridView1.ShowColumnHeaderCheckBox = true;//此处设为true
DataGridViewColumnHeaderCellW ch = new DataGridViewColumnHeaderCellW();
ch.OnCheckBoxClicked += new datagridviewcheckboxHeaderEventHander(OnCheckBoxClicked);
//第三列为DataGridViewCheckBoxColumn
DataGridViewCheckBoxColumn checkboxCol = this.dataGridView1.Columns[] as DataGridViewCheckBoxColumn;
checkboxCol.HeaderCell = ch;
checkboxCol.HeaderCell.Value = string.Empty;//消除列头checkbox旁出现的文字
}

总结

在研究一个新的东西时,我一般是先实现粗糙的功能,由浅入深渐渐细化这么一个演变的过程,毕竟灰姑娘一下要变成白雪公主也是要有个过程的。

元芳,你怎么看?

小菜的系统框架界面设计-数据的完美呈现(DataGridView扩展)的更多相关文章

  1. 小菜的系统框架界面设计-XiaoCai.WinformUI代码开源

    我的源码分享 曾经,看到别人漂亮的系统界面,合理的布局,可是却没有提供源码,道理很简单,就是有偿提供,实际上对于有些技巧的东西也并没有多么难,只是不懂原理,感觉到困难罢了. 而对于刚毕业的我,求知欲强 ...

  2. 小菜的系统框架界面设计-灰姑娘到白雪公主的蜕变(工具条OutLookBar)

    灰姑娘本身也有自已的优点,但是却可能因为外貌不讨人喜欢,要变成白雪公主却需要有很多勇气和决心去改变自已: 有一颗善良的心 讨人喜爱的外貌   --蜕变-->  我这里讲的是一个工具条的蜕变过程, ...

  3. Java日志系统框架的设计与实现

    推荐一篇好的文章介绍java日志系统框架的设计的文章:http://soft.chinabyte.com/database/438/11321938.shtml 文章内容总结: 日志系统对跟踪调试.程 ...

  4. 基于Hadoop开发网络云盘系统客户端界面设计初稿

    基于Hadoop开发网络云盘系统客户端界面设计初稿 前言: 本文是<基于Hadoop开发网络云盘系统架构设计方案>的第二篇,针对界面原型原本考虑有两个方案:1.类windows模式,文件夹 ...

  5. Winform XiaoCai.WinformUI 框架界面设计

    开源用户界面和布局的套件XiaoCai.WinformUI(美化用户界面利器) http://www.cnblogs.com/aganqin/p/3400453.html 源码下载:https://g ...

  6. 苹果IOS与谷歌 android系统的UI设计原则

    一.苹果为IOS的界面设计提出了六大原则: 1.整体美学 整体美学指的是一个应用的表现和行为与它的功能完美集成,传达连贯的信息. 人们关心一个应用是否提供它承诺的功能,但他们也被应用的外观和行为强烈影 ...

  7. [自制操作系统] BMP格式文件读取&图形界面系统框架/应用接口设计

    本文将介绍在本人JOS中实现的简单图形界面应用程序接口,应用程序启动器,以及一些利用了图形界面的示例应用程序. 本文主要涉及以下部分: 内核/用户RW/RW调色板framebuffer共享区域 8bi ...

  8. [课程设计]Scrum 1.3 多鱼点餐系统开发进度(系统主界面框架&美化)

    Scrum 1.3 多鱼点餐系统开发进度(系统主界面框架&美化) 1.团队名称:重案组 2.团队目标:长期经营,积累客户充分准备,伺机而行 3.团队口号:矢志不渝,追求完美 4.团队选题:餐厅 ...

  9. 基于WPF系统框架设计(3)-Fluent Ribbon界面布局

    一个系统框架除了功能菜单导航,有系统内容显示区域,系统状态栏. Silver: Blue: Black: 系统界面设计,就不进行技术细节介绍了,主题以框架设计为主,Xaml源码参考: <Flue ...

随机推荐

  1. struts (一)

    1.jar 2.web.xml <?xml version="1.0" encoding="UTF-8"?> <web-app id=&quo ...

  2. js替换字符串中全部“-”

    alert("2014-03-22".replace('-','')); alert("2014-03-22".replace(/-/g,'')); 第一个运行 ...

  3. 让我苦苦寻找的那段代码---springmvc的ajax前后台交互

    导入jar包: web.xml <servlet> <servlet-name>spmvc</servlet-name> <servlet-class> ...

  4. PostgreSQL 数据迁移

    新主机PostgreSQL需要事先建立和原主机名称相同的用户和数据库. 备份原主机数据库 pg_dump -U <UserName> -p <PortNum> <DBNa ...

  5. 11gr2 alert日志中报TNS-12535 TNS-00505原因及解决方法 (转载)

    前面新装了11GR2 RAC,某天在做巡检的时候发现alert日志中存在如下报错:Fatal NI connect error 12170. VERSION INFORMATION:        T ...

  6. php中引用符号(&)的使用详解

    php的引用就是在变量或者函数.对象等前面加上&符号,在PHP 中引用的意思是:不同的名字访问同一个变量内容,下面介绍如何使用PHP的引用 与C语言中的指针是有差别的.C语言中的指针里面存储的 ...

  7. Kung fu

    1. originPeople in Primitive society(原始社会)in order to survive,they have to hunt for food efficiently ...

  8. VB 读取csv文件数据

    Public adoConn As New ADODB.Connection Private Sub csv() adoConn.ConnectionString = "Driver={Mi ...

  9. 在java 中,数组与 List<T> 类型的相互转换

    在java中,数组与List<T> 之前进行互相转换,转换方法可总结为以下几种: 一. 将 数组转换成List<T> 1. 使用 Collections 的addAll 方法 ...

  10. 查看Eclipse版本号的方法

    查看Eclipse版本号的方法如下所示: 1:假设Eclipse已打开Eclipse的菜单栏: Help-->About Eclipse弹出框中会显示一排logo,点击eclipse的那个log ...