2
votes

I have a DataGridView in WinForms (c#) project. Its rows are being formatted if a certain condition is met. Here is the code:

private void dataGridView1_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
{
    foreach (DataGridViewRow Myrow in dataGridView1.Rows)
    {
        string BEFORE_HYPHEN = GetUntilOrEmpty(Convert.ToString(Myrow.Cells[2].Value));
        if (BEFORE_HYPHEN.Length == 2)
        {
        }
        else
        {
            Myrow.DefaultCellStyle.BackColor = Color.Yellow;
            Myrow.DefaultCellStyle.ForeColor = Color.Black;
        }
    }
}

Now, what I want to do is to make the rows with Yellow BackColor appear first (sort according to row background color).

2
what you use as datasource ?Z.R.T.
A data set. dataGridView1.DataSource = DATASET_DATA.Tables[0];theLuckyOne

2 Answers

3
votes

Issues with coloring

You're not using CellFormatting event effectively. You see, this event is getting called for every cell of a grid. You're expected to check one particular cell and assign custom formatting to it. With your implementation you're recalculating the whole grid for every cell.

This is ineffective, but more importantly, this approach will make it harder to sort your grid by backcolor. Formatting is usually the last step of displaying a datagrid. You'll need to somehow detect when the event runs for every cell of a grid and then proceed to sort it.

Instead of using CellFormatting you should probably run the coloring loop only once. You can do it in DataBindingComplete if your grid is databound, or just after initialization if it's not.

Sorting a databoud DataGridView

If your datagridview is databound you're expected to sort the underlying data source, not the grid itself. Perhaps, you'll need to precalculate colors for each row, sort the container and, only after that, bind the DataGridView.

See this questions for implementation ideas:

Update: as you're binding a grid to datatable, we can use the code, published by @TaW in Custom sorting order - DataGridView as a starting point.

Here's a simplistic example:

//we'll need to process this table
var table = DATASET_DATA.Tables[0];

//First, add a column for BackColor and calculate values
//Here I use a simple column of type Color and default order (alphabetically, by color name)
//If you need a more complicated sorting, consider creating a numeric (BackColorOrder) column instead
table.Columns.Add("BackColor", typeof(Color));
foreach (DataRow row in table.Rows)
{
    string BEFORE_HYPHEN = GetUntilOrEmpty(Convert.ToString(row[2]));
    if (BEFORE_HYPHEN.Length == 2)
    {
        //white, or whatever your default color is
        row["BackColor"] = Color.White;
    }
    else
    {
        row["BackColor"] = Color.Yellow;
    }
}

//Assign a sorted binding source as a datasource
var bs = new BindingSource
{
    DataSource = table,
    Sort = "BackColor ASC"
};
dataGridView1.DataSource = bs;
//Hide backcolor from the grid
//If this column has a meaning in your application (some kind of a status?)
//Consider displaying it, so the user will be able to change sort order
dataGridView1.Columns["BackColor"].Visible = false;

...

/// <summary>
/// We're using DataBindingComplete to calculate color for all rows
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void dataGridView1_DataBindingComplete(object sender, DataGridViewBindingCompleteEventArgs e)
{
     //Assign a pre-calculated BackColor for grid rows
     foreach (DataGridViewRow row in dataGridView1.Rows)
     {
          row.DefaultCellStyle.BackColor = (Color)row.Cells["BackColor"].Value;
     }
}

Here's a full, runnable example. The result looks like this:

enter image description here

Sorting a non-databound DataGridView

If your datagridview is not data-bound, you should be able to sort it using Sort(IComparer comparer):

dataGridView1.Sort(new BackColorComparer());

...
/// <summary>
/// Custom comparer will sort rows by backcolor
/// </summary>
private class BackColorComparer : System.Collections.IComparer
{
     public int Compare(object x, object y)
     {
          var row1 = (DataGridViewRow)x;
          var row2 = (DataGridViewRow)y;
          //Sorting by color names, replace with custom logic, if necessary
          return string.Compare(
               row1.DefaultCellStyle.BackColor.ToString(),
               row2.DefaultCellStyle.BackColor.ToString());
     }
}

Make sure to run this code only after you finished calculating BackColor for all the rows.

1
votes

you need to change you datagridview datasource as the following:

var sorted = DATASET_DATA.Tables[0].Select().OrderBy(row =>
{
    string BEFORE_HYPHEN = GetUntilOrEmpty(Convert.ToString(row.ItemArray[2]));
    return BEFORE_HYPHEN.Length == 2;
});
dataGridView1.DataSource = sorted.CopyToDataTable();