王朝网络
分享
 
 
 

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

王朝c#·作者佚名  2006-01-09
宽屏版  字体: |||超大  

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

鼓起勇气贴上这篇帖子,实在不知道究竟是否有人会看。而随着Whidbey的推出,这个问题应该已经不复存在——新的DataGridView控件据说可以直接设置行颜色——不过考虑到Whidbey目前只是测试版,DataGrid控件还在广泛地使用,本文或许能对面临同样问题的朋友稍有帮助。

大家都知道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);

}

}

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
>>返回首页<<
推荐阅读
 
 
频道精选
 
静静地坐在废墟上,四周的荒凉一望无际,忽然觉得,凄凉也很美
© 2005- 王朝网络 版权所有