2

I have a datagridview for which I have included couple of validations like cell value not empty and cell value should be in the range of (1,9). I also wanted to make sure a compute button is enabled only after the entire datagridview is filled with valid values.

I tried to use foreach and check for the rows and cells inside it if the cell value is not empty, but the button is getting enabled immediately just after checking one cell. Checking for the last cell in each row also doesn't work since user can fill the values in any order and we should try to track the point when all the cells are filled and make the button enabled then. If they aren't filled, we have to make the button disabled immediately. Is there a way I can enable a button only if all the cells are filled and validated accordingly.

Below is my code. I am a bit new to C#, I also wanted to know if I am using the right datagridview event to achieve this. Instead of looping through each row and cell to find the value, is there an efficient way to find if all the cells are filled or not in one-go?

Cal.Enabled = false;
private void dataGridView_CellValidating(object sender, DataGridViewCellValidatingEventArgs e)
        {
            int r = e.RowIndex;
            int c = e.ColumnIndex;
foreach (DataGridViewRow row in dataGridView.Rows)
            {
                foreach (DataGridViewCell cell in row.Cells)
                {
                    if ((cell.Value != null) || cell.Value != DBNull.Value || !(String.IsNullOrEmpty(cell.Value.ToString())))
                    {
                        Cal.Enabled = true;
                    }
                }

            }
        }
  • Hint: Don't check for filled cells, check for empty cells instead. – HardCode Mar 04 '20 at 20:42
  • I have tried that too, but it didn't work. – Rohit Venkat Gandhi Mendadhala Mar 04 '20 at 20:51
  • You're setting the enabled state if you find just one cell value matching the criteria you set - probably not the check you wanted. You're never setting the enabled state to false, only true. Additionally, `cell.Value.ToString()` will not always return the value you expect, depending on what you have in that cell.Value (i.e. value/reference types) – slugster Mar 04 '20 at 21:00
  • I have set the enabled state to false initially when the form loads. Sorry, I forgot to add that to the code. Just updated that. – Rohit Venkat Gandhi Mendadhala Mar 04 '20 at 21:02
  • The code is not taking into account the “short circuiting” when using the logical OR (||) operator. From MS… `if (x || y)` Then … _”If x evaluates to true, y is not evaluated.”_ … – JohnG Mar 05 '20 at 01:00
  • Therefore, in the posted `if` statement… `if ((cell.Value != null) || cell.Value != DBNull.Value || !(String.IsNullOrEmpty(cell.Value.ToString())))` Will evaluate such that IF the FIRST condition “`cell.Value != null`” returns ‘true` (meaning the cell value is NOT null but it may be empty)… then the other following condition… `!(String.IsNullOrEmpty(cell.Value.ToString())))` will NOT get evaluated. When an OR conditional finds a true condition there is no need to continue. – JohnG Mar 05 '20 at 01:07

2 Answers2

1

You have to check every cell - and if any one cell is invalid, you must disable the button.

As an aside, I think the behaviour is better when you use the CellEndEdit event, instead of the Validating event. But both sort of work.

private void dataGridView_CellEndEdit(object sender, DataGridViewCellEventArgs e)
{   
    // We assume every cell is valid
    // and then we'll loop until we find one that isn't.    
    var allValid = true; 
    foreach (DataGridViewRow row in dataGridView.Rows)
    {
        foreach (DataGridViewCell cell in row.Cells)
        {
            var v = cell.Value;         
            if(v == null || v == DBNull.Value || string.IsNullOrEmpty(v?.ToString())) {
                // We found an invalid cell!
                allValid = false;
                break;
            }           
        }       
        // a cell in this row was invalid - no need to check the next row
        if(!allValid) break;            
    }

    // Now, if all cells were valid, allValid is still true.
    // If any cell was invalid, it's false. 
    Cal.Enabled = allValid;
}
gnud
  • 77,584
  • 5
  • 64
  • 78
  • Well. This is what I exactly wanted.!!! Thanks a ton and your logic also seems straight forward and clearly understandable. Thank you once again. It didn't work in the validate event for me but worked in the end edit event. – Rohit Venkat Gandhi Mendadhala Mar 05 '20 at 22:21
  • Glad it worked! The same logic sort-of works in the Validate event as well, but the parameters for the method are different, so you can't re-use the whole method directly. But the Validate event isn't triggered until focus leaves the cell, or something like that. It feels more immediate if you use the end edit event. – gnud Mar 06 '20 at 00:02
0

You need to be using "AND" in your condition instead of "OR". Try

if ((cell.Value != null) && cell.Value != DBNull.Value && !(String.IsNullOrEmpty(cell.Value.ToString())))
                    {
                        Cal.Enabled = true;
                    }
samyap
  • 131
  • 1
  • 7
  • That didn't work for me. Its getting enabled immediately after I move the focus to next cell – Rohit Venkat Gandhi Mendadhala Mar 04 '20 at 20:29
  • Hmm. Are there empty cells still? – samyap Mar 04 '20 at 20:29
  • Yes, there are empty cells. – Rohit Venkat Gandhi Mendadhala Mar 04 '20 at 20:31
  • Try to put a breakpoint on your `foreach` and validate the `datagridview` has the correct amount of rows and columns you are expecting – samyap Mar 04 '20 at 20:34
  • The datagridview is already pre-generated with desired no.of rows and columns. The user will be inputting the cell values in it. Since I have already included validation condition for each cell, the user cant skip to the next unless one is correctly filled. But I want the button to be enabled only after all cells are filled correctly, not just one. – Rohit Venkat Gandhi Mendadhala Mar 04 '20 at 20:38
  • My question is more that your variable `dataGridView` may not be what you are expecting it to be. As in it is not looping through all the cells you see on the screen – samyap Mar 04 '20 at 20:48
  • The dataGridView is generated based on a treenode structure. If the treenode have 5elements a 5 * 5 datagridview is created, if treenode has 4 , a 4*4 datagridview is created. Hence I said datagridview size is variable. – Rohit Venkat Gandhi Mendadhala Mar 04 '20 at 20:50
  • Yeah totally understand you there. I am just saying you may be looping through the wrong variable. The best to check that is to debug and see if the count of columns and rows on the screen matches the columns and rows you can see when you debug and hover over the variable `dataGridView` – samyap Mar 04 '20 at 20:52
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/209025/discussion-between-rohit-venkat-gandhi-mendadhala-and-samyap). – Rohit Venkat Gandhi Mendadhala Mar 04 '20 at 20:56