在DataGrid(WinForm)中改变符合指定条件的行颜色的方法

原创 2011年03月31日 08:38:00

      大家都知道DataGrid控件通过其属性TableStyles控制每个对应的DataTable的显示风格,而每个TableStyle又通过其属性GridColumnStyles控制每一列的显示风格,但却没有属性或方法可以直接设置每行数据的显示风格。这或许是出于使用方法考虑(在绑定数据源前当然不知道有哪些行,行中有哪些数据),或许是出于性能考虑(为每行建立显示风格索引的代价会比较大),或者是其他考虑(我没想到的^_^)。但实际工作中这种需求很多,比如“当资源小于某个临界值就变红色显示”之类的。如果可以做到改变行的颜色,应该能满足这些需求中的大部分。然而按照常规方法,在一列当中,每个单元格(即每行)的显示风格都是相同的。

改变DataGrid控件行颜色的基本技巧就是重写DataGridColumnStyle的Paint方法,更改其中的foreBrush和backBrush两个参数,再重新调用基类的Paint方法。当然实际操作中我们不能直接继承DataGridColumnStyle类,而是要从它的子类DataGridTextBoxColumn,DataGridBoolColumn中继承(可惜我们不能在这个继承层次中插入我们自己的类,呵呵)。如下所示:
 public class  DataGridColoredTextBoxColumn : DataGridTextBoxColumn
 { 
  //重载绘制单元格的函数,如果该单元格所在行符合ColoredView中的条件,就改变前景和背景色
  protected override void Paint(System.Drawing.Graphics g, 
   System.Drawing.Rectangle bounds, System.Windows.Forms.CurrencyManager 
   source, int rowNum, System.Drawing.Brush backBrush, System.Drawing.Brush 
   foreBrush, bool alignToRight) 
  { 
   /*在这里加入判断条件,决定是否更改颜色
   if (...)
    backBrush = new SolidBrush(...);
    foreBrush = new SolidBrush(...);
   */
   
   //调用基类的绘制函数
   base.Paint(g, bounds, source, rowNum, backBrush, foreBrush, alignToRight);
  } 
 }

这个方法本身很好理解,我们再为这个类加上一个设置颜色的公共方法,就可以在使用的时候指定颜色了(这里的颜色是广义的概念,对于Brush来说,也可以指定渲染方式)。问题的关键在于我们如何设置if里面的那个条件:我们能看出Paint方法的参数rowNum给出了正在绘制的当前行行号,那么是否可以通过指定行号来决定改变那一行的颜色呢?答案是否定的。首先,rowNum给出的行号是当前显示的行号,而我们在外部通过某些条件选出来的往往是DataSource中的行号,由于排序等操作会改变显示顺序,这两者有可能不一致;其次,我们往往是希望符合一定条件的行变色,而不是特定位置的行变色,如果直接指定行号,就会造成设置的颜色成了DataGrid的背景,有失初衷。

既然如此,我们是不是可以通过rowNum直接取出要判断的那一列的内容,根据它的值来判断是否变色呢?网上有不少例子都是这么实现的,作为展示一个技巧,当然已经足够了,不过实际使用却不太方便。因为这势必要求我们把判断条件("age>20", "name like 'Jack'"之类的)硬编码在方法中,不够灵活,如果有多个地方需要设置不同的条件,岂不是要编写多个类?况且要真正地取出rowNum对应的某一列的值,也不是那么容易的。

要解决上述两个问题,比较理想的思路就是首先想办法取出rowNum在其绑定的dataSource中对应的行,再通过公共方法指定要变色的行,比较两者是否相等,如果相等就按预先设置的Brush更改前景和背景。下面是我找到的一种获取DataSource中对应rowNum的行的方法,通过获取一个当前的DataView实现,也许不够简洁,不过确实可用:
 //获取当前正在显示的DataView
 DataView currentView;
 Type iType = this.DataGridTableStyle.DataGrid.DataSource.GetType();
 if (iType==typeof(System.Data.DataView) )
  currentView = (DataView)(this.DataGridTableStyle.DataGrid.DataSource);
 else if (iType==typeof(System.Data.DataTable) )
  currentView = ((DataTable)(this.DataGridTableStyle.DataGrid.DataSource)).DefaultView;
 else if (iType==typeof(System.Data.DataSet) )
  currentView = ((DataSet)(this.DataGridTableStyle.DataGrid.DataSource)).Tables[this.DataGridTableStyle.MappingName].DefaultView;
 else if (iType==typeof(System.Data.DataViewManager) )
 {
  DataViewManager viewManager = (DataViewManager)(this.DataGridTableStyle.DataGrid.DataSource);
  currentView = viewManager.DataSet.Tables[this.DataGridTableStyle.MappingName].DefaultView;
 }
 else
 { //如果dataSource不符合以上四种类型(应该不会吧^_^),抛出系统错误
  throw(new SystemException()); 
 }
 
 //取出当前行
 DataRow currentRow = currentView[rowNum].Row;
 
找到当前行后就好办了,和预先指定的一系列行做比较,就可以知道是不是应该变色,如下所示:
 //搜索当前行是否在设置行色彩的ColoredView当中
 DataRow currentRow = currentView[rowNum].Row;
 foreach (DataRow coloredRow in m_coloredDataRows) //m_coloredDataRows是一个DataRow类型的数组,是private的成员变量
 {
  if (currentRow == coloredRow) 
  {
   backBrush = m_backBrush;
   foreBrush = m_foreBrush; 
   break;
  }
 }
至此,我们终于给出了if的判断条件,问题也就解决了。为了便于使用,我们还要提供一个公共方法,以及几个私有成员,来供外界设置行和颜色,该方法可以粗略实现如下:
 private System.Data.DataRow[] m_coloredDataRows;
 private System.Drawing.Brush m_foreBrush;
 private System.Drawing.Brush m_backBrush;

 //设置行色彩
 public void SetRowsColor(DataRow[] aDataRows, System.Drawing.Brush aForeBrush, System.Drawing.Brush aBackBrush)
 {
  //设置要改变颜色的行
  m_coloredDataRows = aDataRows;
  //设置前景色
  m_foreBrush = aForeBrush;
  //设置背景色
  m_backBrush = aBackBrush;
 }

使用这个类的方法很简单,下面举一个例子,是用其中dTable是一个DataTable对象,用它的Select方法选出了要变色的行,作为SetRowsColor的实参:
 //设置列以及每列的行样式
 DataGridTableStyle dgTableStyle = new DataGridTableStyle();
 dgTableStyle.MappingName = dTable.TableName;
 foreach (DataColumn eachCol in dTable.Columns)
 {
  DataGridColoredTextBoxColumn dbColumnStyle = new DataGridColoredTextBoxColumn();
  dbColumnStyle.MappingName = eachCol.ColumnName;
  //设置变色行的条件以及前景和背景色
  dbColumnStyle.SetRowsColor(dTable.Select("age>20"), new SolidBrush(Color.White), new SolidBrush(Color.BlueViolet));
  dgTableStyle.GridColumnStyles.Add(dbColumnStyle);
 }
 
 //添加样式到dataGrid1
 dataGrid1.TableStyles.Add(dgTableStyle);
 
当然,如果希望通用型更强,这个类还有很多功能有待完善,比如目前只能设定一组行的颜色,再次设置会替换掉原来的内容,要想设置多组行与颜色的对应,还得添加一些数据结构;还有当前只能设置Brush,实现不了改变字体之类的功能,不过目前我也还没找到好办法(Paint方法以及PaintText方法都没有关于字体的参数)。

完整的测试代码附在下面:
using System.Data;

public class Form2 : System.Windows.Forms.Form
{
 public Form2()
 {
  //
  // Windows 窗体设计器支持所必需的
  //
  InitializeComponent();

  DataTable dTable;

  //创建测试DataTable
  dTable = new DataTable("person");
  //添加测试列
  dTable.Columns.Add(new DataColumn("id",typeof(int)) );
  dTable.Columns.Add(new DataColumn("name",typeof(string)) );
  dTable.Columns.Add(new DataColumn("age",typeof(int)) );
  //添加测试行   
  DataRow newDataRow;
  Random iRandom = new Random();
  for(short i=0;i<20;i++)
  {
   newDataRow = dTable.NewRow();
   newDataRow[0] = i;
   newDataRow[1] = Convert.ToString(iRandom.Next(0,15))+"song";
   newDataRow[2] = iRandom.Next(15,30);
   dTable.Rows.Add(newDataRow);
  }

  //设置列以及每列的行样式
  DataGridTableStyle dgTableStyle = new DataGridTableStyle();
  dgTableStyle.MappingName = dTable.TableName;
  foreach (DataColumn eachCol in dTable.Columns)
  {
   DataGridColoredTextBoxColumn dbColumnStyle = new DataGridColoredTextBoxColumn();
   dbColumnStyle.MappingName = eachCol.ColumnName;
   //设置变色行的条件以及前景和背景色
   dbColumnStyle.SetRowsColor(dTable.Select("age>20"), new SolidBrush(Color.White), new SolidBrush(Color.BlueViolet));
   dgTableStyle.GridColumnStyles.Add(dbColumnStyle);
  }
  
  //添加样式到dataGrid1
  dataGrid1.TableStyles.Add(dgTableStyle);
  
  dataGrid1.SetDataBinding(dTable,"");  
 }
}

public class  DataGridColoredTextBoxColumn : DataGridTextBoxColumn
{ 
 private System.Data.DataRow[] m_coloredDataRows;
 private System.Drawing.Brush m_foreBrush;
 private System.Drawing.Brush m_backBrush;

 //设置行色彩
 public void SetRowsColor(DataRow[] aDataRows, System.Drawing.Brush aForeBrush, System.Drawing.Brush aBackBrush)
 {
  //设置要改变颜色的行
  m_coloredDataRows = aDataRows;
  //设置前景色
  m_foreBrush = aForeBrush;
  //设置背景色
  m_backBrush = aBackBrush;
 }

 //重载绘制单元格的函数,如果该单元格所在行符合ColoredView中的条件,就改变前景和背景色
 protected override void Paint(System.Drawing.Graphics g, 
  System.Drawing.Rectangle bounds, System.Windows.Forms.CurrencyManager 
  source, int rowNum, System.Drawing.Brush backBrush, System.Drawing.Brush 
  foreBrush, bool alignToRight) 
 { 
  //获取当前正在显示的DataView
  DataView currentView;
  Type iType = this.DataGridTableStyle.DataGrid.DataSource.GetType();
  if (iType==typeof(System.Data.DataView) )
   currentView = (DataView)(this.DataGridTableStyle.DataGrid.DataSource);
  else if (iType==typeof(System.Data.DataTable) )
   currentView = ((DataTable)(this.DataGridTableStyle.DataGrid.DataSource)).DefaultView;
  else if (iType==typeof(System.Data.DataSet) )
   currentView = ((DataSet)(this.DataGridTableStyle.DataGrid.DataSource)).Tables[this.DataGridTableStyle.MappingName].DefaultView;
  else if (iType==typeof(System.Data.DataViewManager) )
  {
   DataViewManager viewManager = (DataViewManager)(this.DataGridTableStyle.DataGrid.DataSource);
   currentView = viewManager.DataSet.Tables[this.DataGridTableStyle.MappingName].DefaultView;
  }
  else
  { //如果dataSource不符合以上四种类型(应该不会吧^_^),抛出系统错误
   throw(new SystemException()); 
  }

  //搜索当前行是否在设置行色彩的ColoredView当中
  DataRow currentRow = currentView[rowNum].Row;
  foreach (DataRow coloredRow in m_coloredDataRows)
  {
   if (currentRow == coloredRow) 
   {
    backBrush = m_backBrush;
    foreBrush = m_foreBrush; 
    break;
   }
  }

  //调用基类的绘制函数
  base.Paint(g, bounds, source, rowNum, backBrush, foreBrush, alignToRight);
 }

}

dataGrid根据条件行显示不同的颜色

  • 2014年05月26日 15:07
  • 2.24MB
  • 下载

SqlServer中计算列详解和winform中改变DataGridView中符合条件的字体的颜色和列的颜色

一、目标:  增加“行政处罚下达时间”,“送法院时间”改为“距送法院天数”( “距送法院天数”为当前时间减去“行政处罚下达时间“,随着时间改变,自动改变),如果“距送法院天数”在3个月内,字体为黄色,...

Silverlight 查询DataGrid 中匹配项 ,后台改变选中行颜色

需求:根据关键字(参会人号码或名称)查找参会人,在datagird 中高亮显示 界面:我在界面上增加了一个文本框和按钮,进行查找操作 操作说明: 根据关键字进行搜索:输入关键字 点击查找,如...

DevExpress控件-GridControl根据条件改变单元格/行颜色(Dev GridControl 单元格着色)

DevExpress控件-数据控件GridControl,有时我们需要根据特定条件改变符合条件的行或者单元格颜色达到突出显示目的,现在动起鼠标跟我一起操作吧,对的,要达到这个目的您甚至都不用动键盘. ...
  • luolunz
  • luolunz
  • 2013年05月10日 16:56
  • 5552

Kendo Grid 行样式(根据条件改变行颜色)

方法一:HTML页面,初始化时设置 //isgen == 1 红色(颜色) $("#gridMaster").kendoSmartGrid({ ...

easyui datagrid 批量编辑和提交 并改变修改过单元格的颜色

easyui datagrid 批量编辑和提交 并改变修改过单元格的颜色

datagrid加载数据,列内容显示,改变字体颜色

//1.加载数据  列内容显示蓝色字体 #region 加载数据  列内容显示蓝色字体 //代码出自:三项工作--项目管理系统--项目管理--项目变更--采购方式变更申请 //页面路径:Ope...

改变DataGrid某一行和单元格的颜色

前段时间做WPF项目,需要改变DataGrid某一行的颜色、高度,以及某个单元格的颜色、单元格字体的颜色,自然就必需取到datagrid的一行和一行的单元格,网上也是搜索了好久才找到,记录下来便于使用...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:在DataGrid(WinForm)中改变符合指定条件的行颜色的方法
举报原因:
原因补充:

(最多只允许输入30个字)