如何根据两个单元格中的值绘制 DataGridView 中的选定行?
How can I paint selected rows in a DataGridView based on the values in two of the cells?
我正在使用 semicolon-delimited 文本文件填充 DataGridView,如下所示:
private void ExistingAppntmntRecs_Load(object sender, EventArgs e)
{
DataTable dt = SeparatedValsFileToDataTable(APPOINTMENTS_FILE_NAME, ";");
dataGridViewExistingAppntmntRecs.DataSource = dt;
}
// from (Frank)
public static DataTable SeparatedValsFileToDataTable(string filename, string separatorChar)
{
var table = new DataTable("Filecsv");
using (var sr = new StreamReader(filename, Encoding.Default))
{
string line;
var i = 0;
while (sr.Peek() >= 0)
{
try
{
line = sr.ReadLine();
if (string.IsNullOrEmpty(line)) continue;
var values = line.Split(new[] { separatorChar }, StringSplitOptions.None);
var row = table.NewRow();
for (var colNum = 0; colNum < values.Length; colNum++)
{
var value = values[colNum];
if (i == 0)
{
table.Columns.Add(value, typeof(String));
}
else
{ row[table.Columns[colNum]] = value; }
}
if (i != 0) table.Rows.Add(row);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
i++;
}
}
return table;
}
我现在要做的是将 EndDate 值在当前日期的两个月内的行着色为黄色,在一个月内为橙色,将日期在过去(意味着它们已经失效)的行着色为红色.
有一个可能有效的 PostPaint 事件,但我不知道如何在该事件处理程序中检查行内的单元格内容:
private void dataGridViewExistingAppntmntRecs_RowPostPaint(object sender, DataGridViewRowPostPaintEventArgs e)
{
// What now?
}
这是读取的文件的内容(bogus/test 数据,前面有 header 行):
person;phone;email;org;addr1;addr2;city;st8;zip;visitNum;success;adSizeLoc;meetingLoc;meetingDate;meetingTime;adBeginMonth;adBeginYear;adEndMonth;adEndYear;Notes
B.B. King;2221113333;bbking@blues.com;Virtuosos;1234 Wayback Lane;;Chicago;IL;98765;1;false;Full Page Inside Front Cover;Same as Org Address;4/5/2017 2:03:12 PM;9:00 am;May;2017;May;2018;Lucille was her name
Linda Ronstadt;55577889999;rhondalinstadt@eaglet.com;Eagles Singer;La Canada;;Los Angeles;CA;99988;1;false;Full page Inside Back Cover;Same as Org Address;4/5/2017 2:05:23 PM;9:00 am;May;2017;May;2018;She had some good stuff
如果 adEndMonth + adEndYear 日期等于或少于 2 个月,则整行应为黄色;如果离开 1 个月或更短时间,则为橙色;如果是今天或过去,就把它涂成红色。最后,如果滚石乐队之一是 运行 应用程序,请将其涂成黑色。
这是 PostPaint 事件的一些伪代码,"TODO:" 我不知道该怎么做:
private void dataGridViewExistingAppntmntRecs_RowPostPaint(object sender, DataGridViewRowPostPaintEventArgs e)
{
DateTime twoMonthsLimit = DateTime.Now.AddMonths(2);
DateTime oneMonthLimit = DateTime.Now.AddMonths(1);
int endYear = // TODO: assign adEndYear value
int endMonth = // TODO: assign adEndMonth value
DateTime endDate = new DateTime(endYear, endMonth, 1);
if (twoMonthsLimit > endDate) // TODO: paint row yellow
if (oneMonthLimit > endDate) // TODO: paint row orange
if (endDate < DateTime.Now) // TODO: paint row red
}
如果目标过于简单,突出显示特定日期内的行,然后更改行背景颜色可能是一个更简单的选择。重新绘制行可能是不必要的。我的解决方案只是根据“endMonth”和“endYear”列中的日期更改行背景颜色。
单元格格式设置是一个选项,但它会经常触发,因此无需在每次更改或显示单元格时都进行“着色”检查。如果行已经“着色”,那么唯一要查找的是何时添加新行或更改“endMonth”或“endYear”列中的值。
下面的代码简单地遍历 DataGridView
并根据您描述的条件设置每一行的颜色。获取行颜色的逻辑相当简单(减去将其涂成黑色)。如果日期比今天日期早两个月以上,则将背景色保留为白色。如果日期大于 1 个月但小于 2 个月,则将该行涂成黄色……等
我使用了类似的方法来读取文本文件并创建数据表。希望这有帮助。
DataTable dt;
string filePath = @"D:\Test\Artist.txt";
char delimiter = ';';
public Form1() {
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e) {
dt = GetTableFromFile(filePath, delimiter);
dataGridViewExistingAppntmntRecs.DataSource = dt;
UpdateDataGridColors();
}
private DataTable GetTableFromFile(string filePath, char delimiter) {
List<string[]> allArtists = GetArtistList(filePath, delimiter);
DataTable dt = GetTableColumns(allArtists[0]);
int totalCols = dt.Columns.Count;
DataRow dr;
for (int i = 1; i < allArtists.Count; i++) {
string[] curArtist = allArtists[i];
dr = dt.NewRow();
for (int j = 0; j < totalCols; j++) {
dr[j] = curArtist[j].ToString();
}
dt.Rows.Add(dr);
}
return dt;
}
private List<string[]> GetArtistList(string inFilePath, char inDelimiter) {
string pathToFile = inFilePath;
char delimiter = inDelimiter;
List<string[]> listStringArrays = File.ReadAllLines(pathToFile).Select(x => x.Split(delimiter)).ToList();
return listStringArrays;
}
private DataTable GetTableColumns(string[] allHeaders) {
DataTable dt = new DataTable();
foreach (string curHeader in allHeaders) {
dt.Columns.Add(curHeader, typeof(string));
}
return dt;
}
private Color GetColorForRow(DataRowView dr) {
// paint it black ;-)
if (dr[0].ToString().Equals("Rolling Stones")) {
return Color.Black;
}
DateTime rowDate;
DateTime dateNow = DateTime.Now;
DateTime twoMonthsLimit = dateNow.AddMonths(2);
DateTime oneMonthLimit = dateNow.AddMonths(1);
if (dr != null) {
string rowStringMonth = dr[17].ToString();
string rowStringYear = dr[18].ToString();
string rowStringDate = "1/" + rowStringMonth + "/" + rowStringYear;
if (DateTime.TryParse(rowStringDate, out rowDate)) {
if (rowDate > twoMonthsLimit)
return Color.White;
if (rowDate > oneMonthLimit)
return Color.Yellow;
if (rowDate > dateNow)
return Color.Orange;
if (rowDate.Month == dateNow.Month && rowDate.Year == dateNow.Year)
return Color.Orange;
// this row date is less than todays month date
return Color.Red;
} // else date time parse unsuccessful - ignoring
}
// date is null
return Color.White;
}
private void UpdateDataGridColors() {
Color rowColor;
DataRowView dr;
foreach (DataGridViewRow dgvr in dataGridViewExistingAppntmntRecs.Rows) {
dr = dgvr.DataBoundItem as DataRowView;
if (dr != null) {
rowColor = GetColorForRow(dr);
dgvr.DefaultCellStyle.BackColor = rowColor;
if (rowColor == Color.Black)
dgvr.DefaultCellStyle.ForeColor = Color.White;
}
}
}
private void dataGridViewExistingAppntmntRecs_CellValueChanged(object sender, DataGridViewCellEventArgs e) {
if (e.ColumnIndex == 17 || e.ColumnIndex == 18) {
//MessageBox.Show("End Date Changed");
UpdateDataGridColors();
}
}
private void dataGridViewExistingAppntmntRecs_RowsAdded(object sender, DataGridViewRowsAddedEventArgs e) {
UpdateDataGridColors();
}
我正在使用 semicolon-delimited 文本文件填充 DataGridView,如下所示:
private void ExistingAppntmntRecs_Load(object sender, EventArgs e)
{
DataTable dt = SeparatedValsFileToDataTable(APPOINTMENTS_FILE_NAME, ";");
dataGridViewExistingAppntmntRecs.DataSource = dt;
}
// from (Frank)
public static DataTable SeparatedValsFileToDataTable(string filename, string separatorChar)
{
var table = new DataTable("Filecsv");
using (var sr = new StreamReader(filename, Encoding.Default))
{
string line;
var i = 0;
while (sr.Peek() >= 0)
{
try
{
line = sr.ReadLine();
if (string.IsNullOrEmpty(line)) continue;
var values = line.Split(new[] { separatorChar }, StringSplitOptions.None);
var row = table.NewRow();
for (var colNum = 0; colNum < values.Length; colNum++)
{
var value = values[colNum];
if (i == 0)
{
table.Columns.Add(value, typeof(String));
}
else
{ row[table.Columns[colNum]] = value; }
}
if (i != 0) table.Rows.Add(row);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
i++;
}
}
return table;
}
我现在要做的是将 EndDate 值在当前日期的两个月内的行着色为黄色,在一个月内为橙色,将日期在过去(意味着它们已经失效)的行着色为红色.
有一个可能有效的 PostPaint 事件,但我不知道如何在该事件处理程序中检查行内的单元格内容:
private void dataGridViewExistingAppntmntRecs_RowPostPaint(object sender, DataGridViewRowPostPaintEventArgs e)
{
// What now?
}
这是读取的文件的内容(bogus/test 数据,前面有 header 行):
person;phone;email;org;addr1;addr2;city;st8;zip;visitNum;success;adSizeLoc;meetingLoc;meetingDate;meetingTime;adBeginMonth;adBeginYear;adEndMonth;adEndYear;Notes
B.B. King;2221113333;bbking@blues.com;Virtuosos;1234 Wayback Lane;;Chicago;IL;98765;1;false;Full Page Inside Front Cover;Same as Org Address;4/5/2017 2:03:12 PM;9:00 am;May;2017;May;2018;Lucille was her name
Linda Ronstadt;55577889999;rhondalinstadt@eaglet.com;Eagles Singer;La Canada;;Los Angeles;CA;99988;1;false;Full page Inside Back Cover;Same as Org Address;4/5/2017 2:05:23 PM;9:00 am;May;2017;May;2018;She had some good stuff
如果 adEndMonth + adEndYear 日期等于或少于 2 个月,则整行应为黄色;如果离开 1 个月或更短时间,则为橙色;如果是今天或过去,就把它涂成红色。最后,如果滚石乐队之一是 运行 应用程序,请将其涂成黑色。
这是 PostPaint 事件的一些伪代码,"TODO:" 我不知道该怎么做:
private void dataGridViewExistingAppntmntRecs_RowPostPaint(object sender, DataGridViewRowPostPaintEventArgs e)
{
DateTime twoMonthsLimit = DateTime.Now.AddMonths(2);
DateTime oneMonthLimit = DateTime.Now.AddMonths(1);
int endYear = // TODO: assign adEndYear value
int endMonth = // TODO: assign adEndMonth value
DateTime endDate = new DateTime(endYear, endMonth, 1);
if (twoMonthsLimit > endDate) // TODO: paint row yellow
if (oneMonthLimit > endDate) // TODO: paint row orange
if (endDate < DateTime.Now) // TODO: paint row red
}
如果目标过于简单,突出显示特定日期内的行,然后更改行背景颜色可能是一个更简单的选择。重新绘制行可能是不必要的。我的解决方案只是根据“endMonth”和“endYear”列中的日期更改行背景颜色。
单元格格式设置是一个选项,但它会经常触发,因此无需在每次更改或显示单元格时都进行“着色”检查。如果行已经“着色”,那么唯一要查找的是何时添加新行或更改“endMonth”或“endYear”列中的值。
下面的代码简单地遍历 DataGridView
并根据您描述的条件设置每一行的颜色。获取行颜色的逻辑相当简单(减去将其涂成黑色)。如果日期比今天日期早两个月以上,则将背景色保留为白色。如果日期大于 1 个月但小于 2 个月,则将该行涂成黄色……等
我使用了类似的方法来读取文本文件并创建数据表。希望这有帮助。
DataTable dt;
string filePath = @"D:\Test\Artist.txt";
char delimiter = ';';
public Form1() {
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e) {
dt = GetTableFromFile(filePath, delimiter);
dataGridViewExistingAppntmntRecs.DataSource = dt;
UpdateDataGridColors();
}
private DataTable GetTableFromFile(string filePath, char delimiter) {
List<string[]> allArtists = GetArtistList(filePath, delimiter);
DataTable dt = GetTableColumns(allArtists[0]);
int totalCols = dt.Columns.Count;
DataRow dr;
for (int i = 1; i < allArtists.Count; i++) {
string[] curArtist = allArtists[i];
dr = dt.NewRow();
for (int j = 0; j < totalCols; j++) {
dr[j] = curArtist[j].ToString();
}
dt.Rows.Add(dr);
}
return dt;
}
private List<string[]> GetArtistList(string inFilePath, char inDelimiter) {
string pathToFile = inFilePath;
char delimiter = inDelimiter;
List<string[]> listStringArrays = File.ReadAllLines(pathToFile).Select(x => x.Split(delimiter)).ToList();
return listStringArrays;
}
private DataTable GetTableColumns(string[] allHeaders) {
DataTable dt = new DataTable();
foreach (string curHeader in allHeaders) {
dt.Columns.Add(curHeader, typeof(string));
}
return dt;
}
private Color GetColorForRow(DataRowView dr) {
// paint it black ;-)
if (dr[0].ToString().Equals("Rolling Stones")) {
return Color.Black;
}
DateTime rowDate;
DateTime dateNow = DateTime.Now;
DateTime twoMonthsLimit = dateNow.AddMonths(2);
DateTime oneMonthLimit = dateNow.AddMonths(1);
if (dr != null) {
string rowStringMonth = dr[17].ToString();
string rowStringYear = dr[18].ToString();
string rowStringDate = "1/" + rowStringMonth + "/" + rowStringYear;
if (DateTime.TryParse(rowStringDate, out rowDate)) {
if (rowDate > twoMonthsLimit)
return Color.White;
if (rowDate > oneMonthLimit)
return Color.Yellow;
if (rowDate > dateNow)
return Color.Orange;
if (rowDate.Month == dateNow.Month && rowDate.Year == dateNow.Year)
return Color.Orange;
// this row date is less than todays month date
return Color.Red;
} // else date time parse unsuccessful - ignoring
}
// date is null
return Color.White;
}
private void UpdateDataGridColors() {
Color rowColor;
DataRowView dr;
foreach (DataGridViewRow dgvr in dataGridViewExistingAppntmntRecs.Rows) {
dr = dgvr.DataBoundItem as DataRowView;
if (dr != null) {
rowColor = GetColorForRow(dr);
dgvr.DefaultCellStyle.BackColor = rowColor;
if (rowColor == Color.Black)
dgvr.DefaultCellStyle.ForeColor = Color.White;
}
}
}
private void dataGridViewExistingAppntmntRecs_CellValueChanged(object sender, DataGridViewCellEventArgs e) {
if (e.ColumnIndex == 17 || e.ColumnIndex == 18) {
//MessageBox.Show("End Date Changed");
UpdateDataGridColors();
}
}
private void dataGridViewExistingAppntmntRecs_RowsAdded(object sender, DataGridViewRowsAddedEventArgs e) {
UpdateDataGridColors();
}