Как я могу нарисовать выбранные строки в 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;
}

Что я хочу сделать сейчас, так это покрасить строки, которые имеют значение EndDate в пределах двух месяцев от текущей даты желтым цветом, в течение одного месяца оранжевым, а те, у которых дата в прошлом (что означает, что они истекли) красным.

Существует событие 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 месяц или меньше, оранжевый; если сегодня или в прошлом, покрасьте его в красный цвет. Наконец, если один из Rolling Stones использует приложение, покрасьте его в черный цвет.

Вот некоторый псевдокод для события 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
}

person B. Clay Shannon    schedule 05.04.2017    source источник
comment
Вы можете попробовать использовать для этого событие CellFormatting и в качестве альтернативы вместо использования краски вы можете просто изменить все строки backcolor. Затем добавьте for или foreach в зависимости от того, что вы предпочитаете, чтобы зациклить все строки.   -  person P. Pat    schedule 06.04.2017
comment
Возможно, сложная вещь в этом заключается в том, что мне нужно проверить значение двух ячеек (месяц И год), прежде чем определить, следует ли изменить цвет фона и на что...   -  person B. Clay Shannon    schedule 06.04.2017
comment
Действительно сложно. Я сделал что-то подобное, но сравнил Double, а не DateTime. Может быть, сделать что-то вроде DateTime cellvalue = Convert.ToDateTime(dataGridView1.Rows[i].Cells[1].Value).AddMonths(1); внутри цикла for, а затем попробовать сравнить это с endDate и посмотреть, вызывает ли это событие? Попробую протестировать и посмотреть, что у меня получится.   -  person P. Pat    schedule 06.04.2017


Ответы (1)


Если цель слишком проста, выделите строки, которые попадают в определенные даты, тогда изменение цвета фона строк может быть более простым вариантом. Перекрашивание строк может быть ненужным. Мое решение просто меняет цвет фона строк в зависимости от дат в столбцах «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();
}
person JohnG    schedule 06.04.2017