Checkmate_001
Checkmate_001

Reputation: 54

C# Conditonal Formatting dynamically generated controls

I've attempted to dynamically create tabs depending on how many groups of data I have in a file (settlementPeriod), each with their own table on them.

I've then added the created tables and added them to a List of DataGridViews, in order to manipulate them later.

DataGridView dgv = new DataGridView();
tableList.Add(dgv);

foreach (var dgv in tableList)
    for (int l = 0; l < dgv.Rows.Count; l++)

However, the program returns a null set for the tableRows (dgv.Rows) and never enters the loop. It only returns data for DataGridViews that are not dyanamically generated. (For example if I addded dataGridView1 to the tableList)


I've attempted to iterate through the list of tabs (as there's only one table per tab), but to no success either

foreach(var page in tabList)
    DataGridView dgv = page.Controls.OfType<DataGridView>() as DataGridView;

I've included all relevant code below. Any help is appreciated. For reference "results" is a class of data. Thanks//.

private List<DataGridView> tableList = new List<DataGridView>();

private void CreateTables()
{
        var listItemsBySettlementPeriod = results.GroupBy(items => items.settlementPeriod)
                            .Select(group => group.ToList())
                            .ToList();

        for (int i = 0; i < listItemsBySettlementPeriod.Count(); i++)
        {
            tabControl1.TabPages.Add(listItemsBySettlementPeriod[i][0].settlementPeriod);
            tabList.Add(tabControl1.TabPages[(i + 1)]);

            DataGridView dgv = new DataGridView();
            tableList.Add(dgv);
            dgv.Height = 300;    dgv.Width = 1200;

            DataTable dt = new System.Data.DataTable();
            DataRow row;
            string[] header = {"bidType", "date", "unitID", "price", "offerVolume"};

            for (int j = 0; j < listItemsBySettlementPeriod[i].Count(); j++)
            {
                if (j == 0)
                    for (int k = 0; k < header.Count(); k++)
                        dt.Columns.Add(header[k], typeof(string));

                row = dt.NewRow();
                foreach (var value in listItemsBySettlementPeriod[i])
                {
                    row[0] = value.bidType;
                    row[1] = value.acceptTime;
                    row[2] = value.unitID;
                    row[3] = value.price;
                    row[4] = value.volume;
                }
                dt.Rows.Add(row);
            }
            dgv.DataSource = dt;  
            tabControl1.TabPages[(i + 1)].Controls.Add(dgv);
        }

        foreach (var dgv in tableList)
        {
            for (int l = 0; l < dgv.Rows.Count; l++) //CONDITIONAL FORMATING
            {
                string val = "";
                if (dgv.Rows[l].Cells[0].Value != null)
                    val = dgv.Rows[l].Cells[0].Value.ToString();

                if (val == "OFFER")
                    dgv.Rows[l].DefaultCellStyle.BackColor = Color.OrangeRed;
                else if (val == "BID")
                    dgv.Rows[l].DefaultCellStyle.BackColor = Color.CornflowerBlue;
                else
                    dgv.Rows[l].DefaultCellStyle.BackColor = Color.LightGray;
            }
            dgv.Refresh();
        }
}

Upvotes: 1

Views: 69

Answers (1)

Alexander Petrov
Alexander Petrov

Reputation: 14231

Until the control is actually drawn (shown), no data binding is applied to it, etc.

So remove the last foreach loop from your method.

Do conditional formatting with the RowPrePaint event.

...
dgv.DataSource = dt;
dgv.RowPrePaint += Dgv_RowPrePaint; // subscribe to event
...

Event handler:

private void Dgv_RowPrePaint(object sender, DataGridViewRowPrePaintEventArgs e)
{
    var dgv = (DataGridView)sender;
    var row = dgv.Rows[e.RowIndex];
    var val = row.Cells[0].Value?.ToString();

    if (val == "OFFER")
        row.DefaultCellStyle.BackColor = Color.OrangeRed;
    else if (val == "BID")
        row.DefaultCellStyle.BackColor = Color.CornflowerBlue;
    else
        row.DefaultCellStyle.BackColor = Color.LightGray;
}

Also, do not use dgv.Refresh(). Very often I see in the code how this Refresh method is used for nothing. It is meaningless in this context.

Upvotes: 1

Related Questions