views:

182

answers:

2

I have a DataGridView that is bound to a DataTable, it has a column that is a double and the values need to be between 0 and 1. Here is my code

private void dgvImpRDP_InfinityRDPLogin_CellValidating(object sender, DataGridViewCellValidatingEventArgs e)
{
    if (e.ColumnIndex == dtxtPercentageOfUsersAllowed.Index)
    {
        double percentage;
        if(dgvImpRDP_InfinityRDPLogin[e.ColumnIndex, e.RowIndex].Value.GetType() == typeof(double))
            percentage = (double)dgvImpRDP_InfinityRDPLogin[e.ColumnIndex, e.RowIndex].Value;
        else if (!double.TryParse(dgvImpRDP_InfinityRDPLogin[e.ColumnIndex, e.RowIndex].Value.ToString(), out percentage))
        {
            e.Cancel = true;
            dgvImpRDP_InfinityRDPLogin[e.ColumnIndex, e.RowIndex].ErrorText = "The value must be between 0 and 1";
            return;
        }
        if (percentage < 0 || percentage > 1)
        {
            e.Cancel = true;
            dgvImpRDP_InfinityRDPLogin[e.ColumnIndex, e.RowIndex].ErrorText = "The value must be between 0 and 1";
        }
    }
}

However my issue when dgvImpRDP_InfinityRDPLogin_CellValidating fires dgvImpRDP_InfinityRDPLogin[e.ColumnIndex, e.RowIndex].Value will contain the old value before the edit, not the new value.

For example lets say the old value was .1 and I enter 3. The above code runs when you exit the cell and dgvImpRDP_InfinityRDPLogin[e.ColumnIndex, e.RowIndex].Value will be .1 for that run, the code validates and writes 3 the data to the DataTable.

I click on it a second time, try to leave, and this time it behaves like it should, it raises the error icon for the cell and prevents me from leaving. I try to enter the correct value (say .7) but the the Value will still be 3 and there is now no way out of the cell because it is locked due to the error and my validation code will never push the new value.

Any recommendations would be greatly appreciated.

EDIT -- New version of the code based off of Stuart's suggestion and mimicking the style the MSDN article uses. Still behaves the same.

private void dgvImpRDP_InfinityRDPLogin_CellValidating(object sender, DataGridViewCellValidatingEventArgs e)
{
    if (e.ColumnIndex == dtxtPercentageOfUsersAllowed.Index)
    {
        dgvImpRDP_InfinityRDPLogin[e.ColumnIndex, e.RowIndex].ErrorText = String.Empty;
        double percentage;
        if (!double.TryParse(dgvImpRDP_InfinityRDPLogin[e.ColumnIndex, e.RowIndex].FormattedValue.ToString(), out percentage) || percentage < 0 || percentage > 1)
        {
            e.Cancel = true;
            dgvImpRDP_InfinityRDPLogin[e.ColumnIndex, e.RowIndex].ErrorText = "The value must be between 0 and 1";
            return;
        }
    }
}
+1  A: 

You need to use the FormattedValue property of the DataGridViewCellValidatingEventArgs instance instead of the cell value, as the cell value isn't updated until validation has succeeded:

The text entered by the user through the user interface (UI) becomes the FormattedValue property value. This is the value that you can validate before it is parsed into the cell Value property value. (MSDN)

Stuart Dunkeld
Nope, `dgvImpRDP_InfinityRDPLogin[e.ColumnIndex, e.RowIndex].FormattedValue` = ".1" after I have entered 5
Scott Chamberlain
Nope. You need to look at e.FormattedValue !
Stuart Dunkeld
Ah! thanks I did not even notice formatted value inside e.
Scott Chamberlain
+1  A: 

How about doing something like this? This assumes you are using textbox's in your datagridview, so if you are using some other control, just change it to that. (Although I'm not sure why Stuart Dunkeld answer didnt work, FormattedValue should have the new value in it).

  void dataGridView1_CellValidating(object sender, DataGridViewCellValidatingEventArgs e)
  {
     if (e.ColumnIndex == 0) // dtxtPercentageOfUsersAllowed.Index
     {
        object should_be_new_value = e.FormattedValue;
        double percentage;
        if (dgvImpRDP_InfinityRDPLogin.EditingControl != null)
        {
           string text = dgvImpRDP_InfinityRDPLogin.EditingControl.Text;
           if (!double.TryParse(text, out percentage))
           {
              e.Cancel = true;
              dgvImpRDP_InfinityRDPLogin[e.ColumnIndex, e.RowIndex].ErrorText = "The value must be between 0 and 1";
              return;
           }
           if (percentage < 0 || percentage > 1)
           {
              e.Cancel = true;
              dgvImpRDP_InfinityRDPLogin[e.ColumnIndex, e.RowIndex].ErrorText = "The value must be between 0 and 1";
           }
           else
           {
              dgvImpRDP_InfinityRDPLogin[e.ColumnIndex, e.RowIndex].ErrorText = null;
           }
        }
     }
  }
SwDevMan81
That worked. thanks.
Scott Chamberlain
No problem. I just changed it a little to use the text and not check the type. Should give the same results only a little cleaner, but let me know if it doesnt work and Ill revert the post back.
SwDevMan81
It fails because EditingControll can be null if you are validating and no boxes are currently being edited.
Scott Chamberlain
Ok, I added the check for a null EditingControl.
SwDevMan81