marky
marky

Reputation: 5068

Change cell style of a DataGridView while the user is editing and typing in cell

I need to change the back color of a DataGridView cell based on certain conditions, as the user is editing the cell. Right now I can only change the BackColor after the cell loses focus.

Specifically, while the user is typing in a cell, I need to check the DataTable that the DataGridView is bound to to compare what the user is typing to what value is in the DataTable in the corresponding cell. If it's different, I need to change the BackColor to Yellow. And if the user changes the value in the cell back to the original value in the DataTable, I need to remove the color.

I tried messing around with the KeyPress event, but I can't figure out how to get the specific row/column index of the cell being edited so I can correctly check it's value against the corresponding DataTable's row/column index value.

Upvotes: 2

Views: 1133

Answers (1)

Reza Aghaei
Reza Aghaei

Reputation: 125197

It's not easy, You need to handle a few things:

  • The cell editing control is different from the cell, so when edit is beginning, find the editing control and set the initial color for that by comparing the text with the datasource value.
  • When the editing controls is going to show, handle it's TextChanged event and in the TextChanged event handler, compare the text with the datasource value and colorize textbox based on that.
  • When you finish editing, the value will not push to data source, until after you leave the record or call end edit explicitly, so when edit is ending, push value to the data source.
  • Handle cell painting and colorize the cell.
  • Use a different color for new rows (if you like). They are different from modified rows, they don't have an original version.
  • Since we have handled cell painting, if the values in data source change, the cell will be repainted.

Here is the screen capture:

enter image description here

Here is a working example:

public DataTable GetProducts()
{
    var products = new DataTable();
    products.Columns.Add("Id", typeof(int));
    products.Columns.Add("Name", typeof(string));
    products.Columns.Add("Price", typeof(int));
    products.Rows.Add(1, "Product 1", 100);
    products.Rows.Add(2, "Product 2", 200);
    products.AcceptChanges();
    return products;
}
private void Form1_Load(object sender, EventArgs e)
{
    dataGridView1.AutoGenerateColumns = true;
    dataGridView1.DataSource = GetProducts();
    dataGridView1.EditMode = DataGridViewEditMode.EditOnEnter;
    dataGridView1.EditingControlShowing += dataGridView1_EditingControlShowing;
    dataGridView1.CellPainting += dataGridView1_CellPainting;
    dataGridView1.CellBeginEdit += dataGridView1_CellBeginEdit;
    dataGridView1.CellEndEdit += dataGridView1_CellEndEdit;
}
private void dataGridView1_CellEndEdit(object sender,
    DataGridViewCellEventArgs e)
{
    if (e.ColumnIndex < 0 || e.RowIndex < 0 || e.RowIndex == dataGridView1.NewRowIndex)
        return;
    var drv = dataGridView1.Rows[e.RowIndex].DataBoundItem as DataRowView;
    if (drv != null)
    {
        drv.EndEdit();
    }
}
private void dataGridView1_CellBeginEdit(object sender, 
    DataGridViewCellCancelEventArgs e)
{
    if (e.ColumnIndex < 0 || e.RowIndex < 0 || e.RowIndex == dataGridView1.NewRowIndex)
        return;
    BeginInvoke(new Action(() =>
    {
        var textBox = dataGridView1.EditingControl as DataGridViewTextBoxEditingControl;
        if (textBox != null)
        {
            SetEditingControlColor(textBox);
        }
    }));
}
private void dataGridView1_CellPainting(object sender, 
    DataGridViewCellPaintingEventArgs e)
{
    if (e.ColumnIndex < 0 || e.RowIndex < 0 || e.RowIndex == dataGridView1.NewRowIndex)
        return;
    var drv = dataGridView1.Rows[e.RowIndex].DataBoundItem as DataRowView;
    if (drv != null && drv.Row.HasVersion(DataRowVersion.Original))
    {
        var column = dataGridView1.Columns[e.ColumnIndex].DataPropertyName;
        if (drv.Row[column, DataRowVersion.Current]
            .Equals(drv.Row[column, DataRowVersion.Original]))
        {
            e.CellStyle.BackColor = Color.White;
        }
        else
        {
            e.CellStyle.BackColor = Color.Yellow;
        }
        return;
    }
    e.CellStyle.BackColor = Color.LimeGreen;
}
void dataGridView1_EditingControlShowing(object sender,
    DataGridViewEditingControlShowingEventArgs e)
{
    var textBox = e.Control as DataGridViewTextBoxEditingControl;
    if (textBox != null)
    {
        textBox.TextChanged -= textbox_TextChanged;
        textBox.TextChanged += textbox_TextChanged;
    }
}
private void textbox_TextChanged(object sender, EventArgs e)
{
    var textBox = (DataGridViewTextBoxEditingControl)sender;
    SetEditingControlColor(textBox);
}
void SetEditingControlColor(DataGridViewTextBoxEditingControl textBox)
{
    var dgv = textBox.EditingControlDataGridView;
    var drv = dgv.CurrentCell.OwningRow.DataBoundItem as DataRowView;
    if (drv != null && drv.Row.HasVersion(DataRowVersion.Original))
    {
        var column = dgv.Columns[dgv.CurrentCell.ColumnIndex].DataPropertyName;
        var value = drv.Row[column, DataRowVersion.Original];
        if (textBox.Text.Equals($"{value}"))
        {
            textBox.BackColor = Color.White;
            textBox.Parent.BackColor = Color.White;
        }
        else
        {
            textBox.BackColor = Color.Yellow;
            textBox.Parent.BackColor = Color.Yellow;
        }
        return;
    }
    textBox.BackColor = Color.LimeGreen;
    textBox.Parent.BackColor = Color.LimeGreen;
}

Upvotes: 1

Related Questions