I am populating a DataGridView with a semicolon-delimited text file like so:
private void ExistingAppntmntRecs_Load(object sender, EventArgs e)
{
DataTable dt = SeparatedValsFileToDataTable(APPOINTMENTS_FILE_NAME, ";");
dataGridViewExistingAppntmntRecs.DataSource = dt;
}
// from http://stackoverflow.com/questions/39434405/read-csv-to-datatable-and-fill-a-datagridview (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;
}
What I want to do now is to color the rows which have an EndDate value within two months of the current date yellow, within one month orange, and those with a date in the past (meaning they have lapsed) red.
There is a PostPaint event which may work, but I don't know how to examine cell contents within the row in that event handler:
private void dataGridViewExistingAppntmntRecs_RowPostPaint(object sender, DataGridViewRowPostPaintEventArgs e)
{
// What now?
}
Here is the contents of the file that is read (bogus/test data, with a header row prepended):
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
If the adEndMonth + adEndYear date equates to 2 months or less away, the entire row should be yellow; if 1 month or less away, orange; if today or in the past, paint it red. Finally, if one of the Rolling Stones is running the app, paint it black.
Here is some pseudocode for the PostPaint event, with "TODO:" where I don't know what to do:
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
}
If the goal is too simply, highlight the rows that fall within certain dates, then changing the rows background color may be an easier option. Repainting the rows may be unnecessary. My solution simply changes the rows background color depending on the dates in the “endMonth” and “endYear” columns.
The cell formatting is an option however, it will fire often and placing this “Coloring” checks every time a cell is changed or displayed is unnecessary. If the rows have already been “Colored”, then the only things to look for is when new rows are added or the values in the “endMonth” or “endYear” columns are changed.
Below is code that simply loops through the DataGridView
and sets each row color based on the criteria you described. The logic to get a rows color is fairly straightforward (minus the paint it black). If the date is greater than two months forward from today’s date then leave the background color white. If the date is greater than 1 month but less than 2 months then color the row yellow… etc.
I used a similar approach to read the text file and create the DataTable. Hope this helps.
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();
}