Stopping blank cells in a datagridview - VB.NET - vb.net

I have a DataGridView on one of my forms that the user can edit and then update so changes are made to the database it is linked to. For this reason i do not want any of the cells to be left blank. Currently i am using this code:
If datagrdSnippets.Item(e.ColumnIndex, e.RowIndex).Value Is Nothing Then
' Show the user a message
MsgBox("Please ensure the cell has been given a value")
' Fail validation (prevent them from leaving the cell)
e.Cancel = True
End If
In the cell validating property of the DSG, however when i edit a cell and leave it blank nothing happens. Is there something wrong in my code or do i need to use another method?
Please Note: This is in VB.NET and i am currently using the CellValidating event.
Thanks :)

Value is not the property to be checked in the CellValidating Event, but e.FormattedValue. The Value property you are using in your code does not reflect the current cell value, but the last validated one. Sample code:
Private Sub datagrdSnippets_CellValidating(sender As System.Object, e As System.Windows.Forms.DataGridViewCellValidatingEventArgs) Handles datagrdSnippets.CellValidating
If (e.FormattedValue = "Value I want to avoid") Then e.Cancel = True
End Sub
Note that this event is called more than just when the user inputs a value and thus a MsgBox "without any restriction" shouldn't be put here (you have to set something (boolean flags, for example) making sure that the user is the one provoking this method to be called).

Related

How can cancelling DataGridViewCellValidatingEventArgs replace all event handlers with itself?

I'm having a very strange problem in a VB application. I have a function written like this:
In the innermost condition, two statements are commented out here. These were found to have no effect on the strange behaviour. This is the minimal example I've found causing trouble.
(Note that the names of objects have been changed in this example.)
Private Sub MyForm_CellValidating(ByVal sender As Object, ByVal e As DataGridViewCellValidatingEventArgs) Handles myDGV.CellValidating
Dim dgv As DataGridView = CType(sender, DataGridView)
Select Case dgv.Columns(e.ColumnIndex).Name
Case "uniqueColumn"
' Validate that the values in our unique column are unique.
For i As Integer = 0 To dgv.RowCount - 1
If i <> e.RowIndex Then
' Here i != j, so compare to the value...
If e.FormattedValue = dgv.Rows(i).Cells(e.ColumnIndex).FormattedValue Then
e.Cancel = True
'dgv.ShowRowErrors = True
'dgv.Rows(e.RowIndex).ErrorText = "Data in the unique column must be unique"
End If
End If
Next 'i
Case Else
' Perform no validation.
End Select
End Sub
What trouble, you ask? For some inexplicable reason, whenever the line
e.Cancel = True
is executed, afterwards, nearly all buttons and form widgets in the entire application, including even the close button in its window bar (what a user would use to exit the application) stop doing whatever they previously did and now call this event handler instead.
In other words, commenting out that line (and doing the validation manually when the form is submitted) fixes the problems. I'd like to know why this happens, though. Some pointers:
Here's a list of which things are not affected:
The minimize and maximize button in the top bar.
All objects in its menu bar.
This handler is private to its form class, it's not referenced anywhere else in the application.
I'm at a loss. Just how? What could possibly cause this?
e.Cancel is for stopping the validation when the input is deemed incorrect. This causes the cell to still have focus as the user is expected to correct whatever they did wrong. The CellValidating event will then be raised again whenever the cell is about to lose focus until your code deems the input to be correct.
You can use the Control.CausesValidation property to control whether a control (for instance a button) should raise validation events when it gains focus.

search for the same cell in a different DataGridView

I have a section of code that loops through a second DataGridView, trying to match the same index number from the main DataGridVew that the user interacts with:
Private Sub AllegationsDataGridView_CellEnter(sender As Object, e As EventArgs) Handles AllegationsDataGridView.CellEnter
Try
Dim currentcolumn As DataGridViewColumn =
AllegationsDataGridView.Columns(AllegationsDataGridView.CurrentCell.ColumnIndex)
For Each row As DataGridViewRow In parentgrid.Rows
If row.Cells.Item(0).Value = AllegationsDataGridView.CurrentRow.Cells(0).Value Then
parentgrid.CurrentCell = parentgrid(0, row.Index)
End If
Next
Catch ex As Exception
Debug.Print(ex.Message)
End Try
endsub:
End Sub
The problem is is that the datasource could potentially be thousands and thousands of entries, and I don't want this to loop through everysingle row until it finds the match. I wondered if there was a quicker way to approach this? The only examples I have seen when searching all use either a For Each Row approach, or a Loop Until approach, which would still present the same issue.
I suggest you to build a dictionary, when you initialize your datagridview with your datasource, that makes correspond the row key (AllegationsDataGridView.CurrentRow.Cells(0).Value) with the row index in the parentGrid. Use the datasource, and not the datagrid, to build this dictionary.
You will be able to access fastly to the corresponding row.
From comments: They both use the same datasource
I am not sure why a DGV the user doesnt interact with needs to have the CurrentCell kept in synch because if they are bound to the same datasource, changes to A are seen in B immediately. Nonetheless:
Private Sub dgv1_CellClick(sender As Object,
e As DataGridViewCellEventArgs) Handles dgv1.CellContentClick
If dgv2.Rows.Count = 0 Then Exit Sub
dgv2.CurrentCell = dgv2.Rows(e.RowIndex).Cells(e.ColumnIndex)
End Sub
Here, dgv1 is the user grid, dgv2 is the other ("parent" in your code?).
The For/Each iteration is not needed if they share a DS because the same data will be at each row and each column index. It will work even if the user has reordered the columns because the column index stays the same, just an internal DisplayIndex changes.
This uses the row and column indices from the DataGridViewCellEventArgs to set the CurrentCell. The Exit Sub is to account for starting up when one may have rows and not the other.
You may want to play with which event to respond to. CellContentClick seems least useful: if they click on any cell whitespace, it doesnt fire. It will also crash if the can click on a cell in the parent/dgv2 grid. CellEnter will also crash if they click on dgv2 directly.
CellClick seems to work okay, but there is the very slightest of delays before they synch up.

Validating entered values in DataGridView Cell using VB.Net

I'm using VB.Net 2008 and trying to validate a certain cell with certain values like:
In DataGridView1 i want to check the entered data in column 1 and cell 1 if it's less than 10 or not so i used the following code
Private Sub DataGridView1_CellValidating(ByVal sender As Object, ByVal e As System.Windows.Forms.DataGridViewCellValidatingEventArgs) Handles DataGridView1.CellValidating
If DataGridView1.CurrentCell.ColumnIndex = 1 Then
If DataGridView1.Rows(e.RowIndex).Cells(1).Value < 10 Then
DataGridView1.Rows(e.RowIndex).ErrorText = "Not Less Than 10"
e.Cancel = True
End If
End If
End Sub
The problem is: every time i try to enter any value in this cell it see nothing (Empty Value) unless if it was already has a value before i start to edit it and always use this value regardless of any new value i write
so how do i validate those cells to not allow users to leave this cell unless it get the right value
Note : CellValidated is working perfectly but it has no e.cancel to prevent users from leaving this cell
I know this is old, but in order to validate the actual value you need to use DataGridView1.Rows(e.RowIndex).Cells(1).FormattedValue, which will give you the modified value. By using DataGridView1.Rows(e.RowIndex).Cells(1).Value you will always get the previous value (uneditted, if the cell is editted for the first time you will get the empty value you see). Note that the FormattedValue works only in the CellValidating method.
Hope this helps anyone who passes by this question. ^^

How to prevent negative integers and blank inputs using DataError event in vb.net

I have a datagridview bound to a dataset. My goal for my datagridview is to prevent the user from entering negative integers and leaving the datagridviewcell blank. I wish to have some sort of error message or message-box to tell the user that their entry is invalid. Here is what I have so far, hopefully it can give you a starting point. I greatly appreciate any help or suggestions you may give.
Private Sub DataGridView1_DataError(ByVal sender As Object, _
ByVal e As DataGridViewDataErrorEventArgs) _
Handles DataGridView1.DataError
If CInt(e.Exception.Message, "Input string was not in a correct format.") < 0 Then
MessageBox.Show("Please Enter a positive Value")
'This will change the number back to original
DataGridView1.Rows(e.RowIndex).Cells(e.ColumnIndex).Value = " "
End If
Have a look at the documentation for DataGridView's CellValidating event: http://msdn.microsoft.com/en-us/library/system.windows.forms.datagridview.cellvalidating.aspx
Attaching a handler for this event allows you to check whether the new value is:
empty
not a number
a negative number
(in that order) and cancel the change if any one of those conditions are true.
EDIT
I'm not sure if this is a coincidence, but you can just copy and paste the example code from the documentation. It does exactly what you're trying to do.

Is there any other way to validate textbox values in VB.net

I am trying to validate textbox values during runtime in vb.net I have following code which is validating txtno from database table tblmachines. But i have problem with chartype and stringtype. Is there any other solution to fix that problem?
Private Sub txtno_KeyPress(ByVal sender As System.Object, ByVal e As System.Windows.Forms.KeyPressEventArgs) Handles txtno.KeyPress
If e.KeyChar = Microsoft.VisualBasic.ChrW(Keys.Return) Then
e.Handled = True
If (Me.txtno.Text = "") Then
Interaction.MsgBox("!!!!!!!!Machine number can not be empty. Please Correct.!!!!!!!!", &H40, "Check Machine Number")
Me.txtno.Focus()
ElseIf (Me.txtno.Text = "0") Then
Me.txtturnover.Focus()
Else
Dim table As DataTable = Me.DataSet1.Tables.Item("tblmachines")
Dim defaultView As DataView = table.DefaultView
defaultView.RowFilter = ("local_no='" & Me.txtno.Text & "'")
If ((Char.IsLetter(CharType.FromString(Me.txtno.Text)) Or (defaultView.Count = 0)) Or (StringType.StrCmp(Me.txtno.Text, "", False) = 0)) Then
Interaction.MsgBox("This machine is not on database. Please correct machine number.", &H40, "Check Machine Number")
Me.txtno.Focus()
Else
Me.txtturnover.Focus()
End If
End If
End If
I think you'd be better off using validation from the Winforms library than in the KeyPress event. KeyPress is going to cause a lot of validation scripts to be run and will bog down your app.
I think you should do the validation in the following steps
Check to ensure that there is data in the texbox
Validate that the data entered in the textbox is in the proper format. You can use regular code, or possibly a RegEx for that.
Validate that the number entered is a part of the database. I made it a habit reset the filters to a blank string before applying any new filters to the table.
The good part about using inbuilt validation is that you do not have to worry about moving focus around.
The control has a property called CausesValidation - if you set it to true (which it already is) then this control will run the validation code. If you do not want the control to run validation code, you can turn the property to False.
The validation happens as Focus shifts - so when you focus off a control, it's validation events are fired.
The events Validating and Validated are commonly used for this purpose. You can put your code validation in there instead of putting it on the KeyPress.
This is not the proper way to let the user input this specific data. You've got a list of valid entries available from your database. Put them in a ComboBox so the user doesn't have to guess and can't get it wrong.