如何基于两个单元格中的值在DataGridView中绘制选定的行?

问题描述:

我填充用分号分隔文本文件,像这样一个DataGridView:如何基于两个单元格中的值在DataGridView中绘制选定的行?

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; 
} 

我想现在要做的就是颜色,这有两个月的当前日期黄色内的结束日期值的行内一个月橙色,以及过去的日期(意思是已经失效)的红色。

有可能工作PostPaint事件,但我不知道如何在该事件处理程序检查行中的单元格内容:

private void dataGridViewExistingAppntmntRecs_RowPostPaint(object sender, DataGridViewRowPostPaintEventArgs e) 
{ 
    // What now? 
} 

这里是读取文件的内容(伪造/测试数据,具有标题行添附):

person;phone;email;org;addr1;addr2;city;st8;zip;visitNum;success;adSizeLoc;meetingLoc;meetingDate;meetingTime;adBeginMonth;adBeginYear;adEndMonth;adEndYear;Notes 
B.B. King;2221113333;[email protected];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;[email protected];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 
} 
+1

您可以尝试使用'CellFormatting'事件作为替代,而不是使用绘画,只需更改整行'backcolor'。然后添加一个'for'或'foreach',无论你喜欢什么来循环所有行。 –

+0

关于这可能很棘手的事情是,我必须检查两个单元格(月和年)的值,然后再确定是否要更改背景颜色,以及... –

+1

确实很棘手。我做了类似的事情,但比较了'Double'而不是'DateTime'。也许做'DateTime cellvalue = Convert.ToDateTime(dataGridView1.Rows [i] .Cells [1] .Value).AddMonths(1);'在'for'循环内,然后尝试与'endDate'比较,看看是否它触发事件?要试试看,看看我得到了什么。 –

如果目标过于简单,彰显属于确定的日期内的行,那么更改行背景颜色可能更容易。重新绘制行可能是不必要的。我的解决方案只是根据“endMonth”和“endYear”列中的日期更改行背景颜色。

单元格格式化是一个选项,但是它会经常启动,并且每次更改或显示单元格时都会放置此“着色”选项。如果行已经是“彩色”,那么唯一需要查找的是添加新行或者更改“endMonth”或“endYear”列中的值。

下面是简单循环遍历DataGridView并根据您描述的标准设置每一行颜色的代码。获取行颜色的逻辑非常简单(减去黑色的颜色)。如果日期从今天的日期开始大于两个月,则背景颜色保持白色。如果日期大于1个月但小于2个月,则将行黄色...等。

我使用类似的方法来读取文本文件并创建DataTable。希望这可以帮助。

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(); 
}