user6789238
user6789238

Reputation:

DataGridView CellFormatting performance issue

How to fix CellFormatting "slow scrolling" performance issue?

Using this code to copy decrypted values from encrypted column to another column:

private void grid_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
{
    if (e.ColumnIndex < 0 || e.RowIndex < 0)
        return;

    var columnB = grid.Columns[e.ColumnIndex];
    if (columnB.Name != "B")
        return;

    var value = grid.Rows[e.RowIndex].Cells["A"].Value;
    if (value == null || value == DBNull.Value)
        return;

    e.Value = Decrypt(value.ToString());
}

Upvotes: 3

Views: 2394

Answers (2)

NoWar
NoWar

Reputation: 37633

Dont use CellFormating method at all.

I found very well working solution finally.

Here is my code.

dgvTrucksMaster.SuspendLayout();
dgvTrucksMaster.DataSource = calendar.FailureCalendarDetails.OrderBy(x => x.MachineFullName).ToList();

foreach (DataGridViewRow row in dgvTrucksMaster.Rows)
{
    if (Convert.ToDouble(row.Cells["Decade1Hours"].Value) > 0)
    {
        row.Cells["Decade1Hours"].Style.BackColor = Color.LightGreen;
    }

    if (Convert.ToDouble(row.Cells["Decade1Hours"].Value) < 0)
    {
        // row.DefaultCellStyle.BackColor = Color.LightSalmon;
        row.Cells["Decade1Hours"].Style.BackColor = Color.LightSalmon;
    }

    if (Convert.ToDouble(row.Cells["Decade2Hours"].Value) > 0)
    {
        row.Cells["Decade2Hours"].Style.BackColor = Color.LightGreen;
    }

    if (Convert.ToDouble(row.Cells["Decade2Hours"].Value) < 0)
    {
        // row.DefaultCellStyle.BackColor = Color.LightSalmon;
        row.Cells["Decade2Hours"].Style.BackColor = Color.LightSalmon;
    }

    if (Convert.ToDouble(row.Cells["Decade3Hours"].Value) > 0)
    {
        row.Cells["Decade3Hours"].Style.BackColor = Color.LightGreen;
    }

    if (Convert.ToDouble(row.Cells["Decade3Hours"].Value) < 0)
    {
        // row.DefaultCellStyle.BackColor = Color.LightSalmon;
        row.Cells["Decade3Hours"].Style.BackColor = Color.LightSalmon;
    }

    if (Convert.ToDouble(row.Cells["DecadeMonthHours"].Value) > 0)
    {
        row.Cells["DecadeMonthHours"].Style.BackColor = Color.LightGreen;
    }

    if (Convert.ToDouble(row.Cells["DecadeMonthHours"].Value) < 0)
    {
        // row.DefaultCellStyle.BackColor = Color.LightSalmon;
        row.Cells["DecadeMonthHours"].Style.BackColor = Color.LightSalmon;
    }

    for (int i = 0; i < 61; i++)
    {
        if (Convert.ToDouble(row.Cells[string.Format("D{0}", i + 1)].Value) < 0)
        {
            row.Cells[string.Format("D{0}", i + 1)].Style.BackColor = Color.LightSalmon;
        }


        if (Convert.ToDouble(row.Cells[string.Format("D{0}", i + 1)].Value) > 0)
        {
            row.Cells[string.Format("D{0}", i + 1)].Style.BackColor = Color.LightGreen;
        }
    }
}

dgvTrucksMaster.ResumeLayout();

As you see from the code the key is to change CellFormating after you apply Data Source and before ResumeLayout method.

Just try it and you will satisfy with result.

Oh! And make sure you do it within BeginInvoke((Action)(() => { // Some code }); code. So please get and prepare Data Source asynchronously.

Upvotes: 1

Reza Aghaei
Reza Aghaei

Reputation: 125197

If the performance issue is because of Decrypt method, you should avoid using it in CellFormatting as mentioned in remarks part of the event's documentations:

The CellFormatting event occurs every time each cell is painted, so you should avoid lengthy processing when handling this event.

what solution can I use to provide value for the second column based on first column?

You can use either of these options:

  1. Add second column to DataGridView and provide the value in a for loop.
  2. Add second column to your data source (for example your DataTable) and provide the value in a for loop.

Example

In the below example, it doesn't make any difference if you load data from database. But to provide a minimal complete verifiable example, I created DataTable myself. In both examples LoadData method, loads a DataTable:

private DataTable LoadData()
{
    var dt = new DataTable();
    dt.Columns.Add("ExistingColumn");
    dt.Rows.Add("x");
    dt.Rows.Add("y");
    dt.Rows.Add("z");
    return dt;
}

Example 1 - Add Column To DataGridView

var dt = LoadData();
dataGridView1.DataSource = dt;
//Add new column to DataGridView
var newColumn = new DataGridViewTextBoxColumn();
newColumn.HeaderText = "NewColumn";
newColumn.Name = "NewColumn";
dataGridView1.Columns.Add(newColumn);
//Copy Values
foreach (DataGridViewRow r in this.dataGridView1.Rows)
{
    if(!r.IsNewRow)
        r.Cells["NewColumn"].Value = Decrypt(r.Cells["ExistingColumn"].Value.ToString());
}

Example 2 - Add Column to DataTable

var dt = LoadData();
dataGridView1.DataSource = dt;
//Add new column to DataTable
dt.Columns.Add("NewColumn");
//Copy Values
foreach (DataRow r in dt.Rows)
    r["NewColumn"] = Decrypt(r.Field<string>("ExistingColumn");

Upvotes: 3

Related Questions