Issue with binding and DBNull. Exception raised only once - vb.net

I have a datatable with two columns C1 & C2. (C1 has AllowDBNull = false). The datatable is created as follows :
Private Function GetDataTable() As DataTable
Dim DT As New DataTable
'Create the first column
Dim C As New DataColumn("C1")
C.AllowDBNull = False
DT.Columns.Add(C)
'Second column
DT.Columns.Add(New DataColumn("C2"))
Return DT
End Function
Then I have a form with two text boxes bound to the datatable :
Dim DT As DataTable = GetDataTable()
Dim CurrencyManager As CurrencyManager = CType(Me.BindingContext(DT), CurrencyManager)
'Add the bindings
TextBox1.BindingContext = Me.BindingContext
TextBox2.BindingContext = Me.BindingContext
TextBox1.DataBindings.Add(New Binding("text", DT, "C1", True, DataSourceUpdateMode.OnValidation))
TextBox2.DataBindings.Add(New Binding("text", DT, "C2", True, DataSourceUpdateMode.OnValidation))
'Set the null value of the Textbox1
TextBox1.DataBindings(0).NullValue = ""
I'm setting the NullValue of the textBox1 such that whenever the textbox is "", it should be considered as DBNull.
I insert a new row using the CurrencyManager :
'Insert a new row
CurrencyManager.AddNew()
'Fill the two columns...
Dim Row As DataRowView = CurrencyManager.Current
Row.Row.Item(0) = "Column 1 Value"
Row.Row.Item(1) = "Column 2 Value"
'Validate the entry
CurrencyManager.EndCurrentEdit() 'No issue here since
Now when the user clears the FirstTextBox (which datatable column has AllowDBNull false) if I run the following code twice. The first time an exception is raised and the msgbox is displayed, however the second time it doesn't raise an exception and it takes back the previous value which is "Column 1 Value" and the column is not anymore dbnull.
Try
CurrencyManager.EndCurrentEdit()
Catch ex As Exception
msgbox("The field C1 can not be empty")
End Try
My question is : is there any way to make the last code always raise an exception when the field is empy ?
Cheers,

Assuming that I am understanding your goal correctly, then something like this should work.
Private Sub TextBox1_Validating(sender As Object, e As CancelEventArgs) Handles TextBox1.Validating
Try
CurrencyManager.EndCurrentEdit()
Catch ex As Exception
MsgBox("The field C1 can not be empty")
TextBox1.DataBindings(0).WriteValue() ' push the value to the datasource
e.Cancel = True
End Try
End Sub
Edit: I just want to state that this use of an exception for validation is not recommended as you could easily validate the text without using an exception. This also assumes that this could is placed in the validating event; an assumption on my part that my be incorrect.

Related

Copy two different datagridview to be one datagridview

My initial code:
Private Sub Transfer_Click(ByVal sender As Object, ByVal e As System.Windows.Forms.DataGridViewCellEventArgs) Handles DataGridView6.CellContentClick
Dim i As Integer
vTableTransfer = New DataTable
vTableTransfer.Columns.Add("Name", GetType(String))
vTableTransfer.Columns.Add("Type", GetType(String))
vTableTransfer.Columns.Add("Len", GetType(Double))
vTableTransfer.Columns.Add("ID", GetType(Double))
vTableTransfer.Columns.Add("OD", GetType(Double))
Try
For i = 0 To DataGridView6.Rows.Count - 3
If DataGridView6.Rows(i).Cells("Transfer").Value = True Then
vRow = vTableTransfer.NewRow
vRow.Item(0) = DataGridView13.Rows(i).Cells(0).Value
vRow.Item(1) = DataGridView6.Rows(i).Cells("Type").Value
vRow.Item(2) = DataGridView6.Rows(i).Cells("Len").Value
vRow.Item(3) = DataGridView13.Rows(i).Cells(2).Value
If IsDBNull(vRow.Item(3)) Then DataGridView13.Rows(i).Cells(2).Value = 0
If DataGridView13.Rows(i).Cells(2).Value = 0 Then DataGridView13.Rows(i).Cells(2).Value=DataGridView5.Columns.Item(1)
vRow.Item(4) = DataGridView6.Rows(i).Cells("OD").Value
If IsDBNull(vTableTransfer.Rows) Then Exit Sub
vTableTransfer.Rows.Add(vRow)
End If
Next
DataGridView12.DataSource = vTableTransfer
Catch ex As Exception
End Try
End sub
I have three datagridview( dgv6 & dgv13 & dgv5) where dgv13 is copy from dgv5 then copy the data to be one datagridview (dgv12) by using checkbox column in dgv6, there are 12 row data on dgv6 and 6 row in dgv13, the program was running well after data on dgv13 empty ( count step -7) then the program was stop catch by DBnull exception. my attemp to are to keep fill data on dgv12 instead event no row data in dgv13 which cacth dbnull where they stop then copy previous cell from dgv13 to finish transfering data to dgv12.
I have trial to cacth dbnull and put put some code to do keep filling data on dgv12 but seem like doesn't work, is it possible todo that or any other methode please advise...many Thanks...
I think i found some tricky, that working fine to avoid catch by dbnull, just continue write some value on dgv13 while checkbutton_click checked on dgv6 so dgv13 continue add value on row instead add value on dgv12.
For i = 0 To DataGridView6.Rows.Count - 3
If DataGridView6.Rows(i).Cells("Transfer").Value = True Then
vRow = vTableLink.NewRow
vRow.Item(0) = ("OH").ToString
vRow.Item(1) = ("0").ToString
vRow.Item(2) = ("0").ToString
If IsDBNull(vTableLink.Rows) Then Exit Sub
vTableLink.Rows.Add(vRow)
End If

Mutually Exclusive Comboboxes?

So, I've got 4 Comboboxes. They all share the same list of options, lets say Apple, Banana, Carrot, Dill.
However, once the user selects one, that selection should not be available in the other comboboxes. E.g. if they pick Apple in Combobox1, then the only selections available in Combobox2, 3, and 4 should be Banana, Carrot, and Dill.
Is there a good way to do this? I originally thought to link the boxes datasource to a list containing the options, but they need separate datasources for separate choices.
Radio and checkboxes aren't really an option in the actual program, as the list of options is much larger than 4. A Combobox seems to be the best way to represent the user's available choices here.
Here's a fairly simple way to do what you are asking. This code assumes that the datasource uses an integer value to keep track of the items. If you are using the string value itself {Apple, Banana, etc.} as the id, the code will need to be amended slightly. If you need further help let me know but hopefully this gets you on the right track.
You can test this by creating a new blank form (Form1) and drop 4 combo boxes onto it (ComboBox1, ComboBox2, ComboBox3, ComboBox4). Copy/paste this code over top of the form code and run to see how it works:
Public Class Form1
Dim oComboBoxArray(3) As ComboBox
Dim bPreventSelectedChange As Boolean = False
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
' Set up an array with the combo box references to reduce code size by using loops later
oComboBoxArray(0) = Me.ComboBox1
oComboBoxArray(1) = Me.ComboBox2
oComboBoxArray(2) = Me.ComboBox3
oComboBoxArray(3) = Me.ComboBox4
' Populate all four combo boxes with the same datasource to start
For Each oCbo In oComboBoxArray
PopulateDataSource(oCbo)
Next
End Sub
Private Sub PopulateDataSource(oCombo As ComboBox, Optional nIdToSelect As Integer = 0)
bPreventSelectedChange = True ' Prevent code in ComboBox_SelectedIndexChanged from executing while we change the datasource
' Using manually populated datatable as datasource because it's quick and easy to use
Dim dt As New DataTable
Dim dr As DataRow
dt.Columns.Add("ID", GetType(Int32))
dt.Columns.Add("Name", GetType(String))
' Need to have some kind of "Please select an item:" in the list or else we will be unable to clear an already selected combo box
dr = dt.NewRow
dr("ID") = 0
dr("Name") = "Select..."
dt.Rows.Add(dr)
' If you are populating from a database or other dynamic source you will only have one of these 'if' statements within a loop
If CheckSkipItem(oCombo, 1) = False Then
dr = dt.NewRow
dr("ID") = 1
dr("Name") = "Apple"
dt.Rows.Add(dr)
End If
If CheckSkipItem(oCombo, 2) = False Then
dr = dt.NewRow
dr("ID") = 2
dr("Name") = "Banana"
dt.Rows.Add(dr)
End If
If CheckSkipItem(oCombo, 3) = False Then
dr = dt.NewRow
dr("ID") = 3
dr("Name") = "Carrot"
dt.Rows.Add(dr)
End If
If CheckSkipItem(oCombo, 4) = False Then
dr = dt.NewRow
dr("ID") = 4
dr("Name") = "Dill"
dt.Rows.Add(dr)
End If
oCombo.DataSource = dt
oCombo.DisplayMember = "Name"
oCombo.ValueMember = "ID"
oCombo.SelectedValue = nIdToSelect ' Set value to either a) the "Select..." item or b) the item that was selected previously depending on the situation
bPreventSelectedChange = False ' Allow code in ComboBox_SelectedIndexChanged to be executed by user again
End Sub
Private Function CheckSkipItem(oCombo As ComboBox, nID As Integer) As Boolean
Dim bSkip As Boolean = False
' Loop through all combo boxes and see if this id has already been chosen in another combo box
For Each oCbo In oComboBoxArray
If oCbo IsNot oCombo AndAlso oCbo.SelectedValue = nID Then
' It has been chosen already so it is not valid for the current combo box that we are checking
bSkip = True
Exit For
End If
Next
Return bSkip
End Function
Private Sub ComboBox_SelectedIndexChanged(sender As Object, e As EventArgs) Handles ComboBox1.SelectedIndexChanged, ComboBox2.SelectedIndexChanged, ComboBox3.SelectedIndexChanged, ComboBox4.SelectedIndexChanged
' Jump out of this event if the bPreventSelectedChange boolean is set to true (ie. if the combo box is being repopulated)
If bPreventSelectedChange = False Then
' A value was chosen by the user. Reset all other combo box datasources and remove the recently selected value
For Each oCbo As ComboBox In oComboBoxArray
If sender IsNot oCbo Then
PopulateDataSource(oCbo, If(oCbo.SelectedValue = Nothing, 0, oCbo.SelectedValue))
End If
Next
End If
End Sub
End Class

System.NullReferenceException on a ForEach of a datagrid

So all is in the question, I have a datagrid view who's parcoured by a foreach in his rows collection like so dataGridView1.Rows and I get and error of null type in the second if of the for each
Sub DataColumnFirstDouble(ByRef dGridView As DataGridView, ByVal iCol As Integer)
Dim bFirstRow As Boolean = False
Dim sTemp As String = ""
For Each RW As DataGridViewRow In dGridView.Rows
If (bFirstRow) Then
If (RW.Cells(iCol).Value.ToString() = sTemp) Then
RW.Cells(iCol).Selected = True
dGridView.CurrentCell.Style.BackColor = Color.LightGreen
dGridView.CurrentCell.Style.ForeColor = Color.White
End If
End If
sTemp = RW.Cells(iCol).Value.ToString()
bFirstRow = True
Next
End Sub
By the way the Datagrid is populated with 1 entry going
LongString, Number, Number
Hello , 8 , 8
The bug occur when I click on a new row also the function is called on the event of row leave
Need some help
By the way what I try to do is to check when the user enter the name in the longstring space who's a primary unique key in a database but It seems I can't find anythings to handle it by vb so I try to parse it every times he leave the rows to check if there's any double
It isn't clear where the error is, you should debug to figure out which variable exactly is null. So I'll assume it's RW.Cells(iCol).Value.
If there's no value in the cell, it might be null. This mean ToString won't work.
If (bFirstRow) Then
If RW.Cells(iCol).Value IsNot Nothing AndAlso RW.Cells(iCol).Value.ToString() = sTemp Then
RW.Cells(iCol).Selected = True
dGridView.CurrentCell.Style.BackColor = Color.LightGreen
dGridView.CurrentCell.Style.ForeColor = Color.White
End If
End If
You could even check if RW.Cells(iCol) exists, maybe it's trying to fetch the data in a cell that doesn't exists in the row.

Setting backgroundcolors in DataGridViewCells depending on the value from SQL (VB.Net winforms)

As the title says.
I collect a bunch of values from a SQL Compact DB, and puts them into a DataGridView. One cell ("Status" in this case) contains a varchar field. I want to set the background color of this field depending on its value.
For example, if this value is == "5" or "V", i want it to be red, if it's "4" or "B" i want it green or something like that.
I've tried with a loop that checks every value in this cell and sets the background color, but when i click in the DataGridView headers to change the order of the values the colors disapears.
And... It does not feel right to achieve this result by looping the values afterwards since there's quite much data.
I collect the values with something like this:
Dim Source as Bindingsource = GetBinding()
Form1.ClientsDataGrid.Columns("CustomerNr").DataPropertyName = "CustNR"
Form1.ClientsDataGrid.Columns("CustomerName").DataPropertyName = "Name"
Form1.ClientsDataGrid.Columns("Status").DataPropertyName = "Status"
Form1.ClientsDataGrid.DataSource = Source
'Just in case, this is how i set the colors now
For Each TblRow As DataGridViewRow In Form1.ClientsDataGrid.Rows
If TblRow.Cells(3).Value.ToString = "5" Or TblRow.Cells(3).Value.ToString = "V" Then
TblRow.Cells(3).Style.BackColor = Color.Red
ElseIf (TblRow.Cells(3).Value.ToString = "4" Or TblRow.Cells(3).Value.ToString = "B" Then
TblRow.Cells(3).Style.BackColor = Color.Green
End If
Next
and the GetBinding() looks something like this:
'blah blah make connections
Dim Com As New SqlCeCommand("SELECT Customernumber AS CustNR, Customername AS Name, Customerstatus AS Status FROM Mytable", Con)
Dim dataAdapter As SqlCeDataAdapter
dataAdapter = New SqlCeDataAdapter(Com)
Dim dataSet As New DataSet
dataAdapter.Fill(dataSet, "Mytable")
Dim bind As BindingSource
bind = New BindingSource(dataSet, "Mytable")
Con.Close()
Com = Nothing
Return bind
Is there a way to set these rules directly to the DataGridView? I can of course do the looping every time i sort the list, but it does'nt feel right?
Do that in rowprepaint event .. apply to the row ..
Private Sub ClientsDataGrid_RowPrePaint(ByVal sender As Object, ByVal e As System.Windows.Forms.DataGridViewRowPrePaintEventArgs) Handles ClientsDataGrid.RowPrePaint
Dim tblRow as DataGridViewRow = ClientsDataGrid.Rows(e.RowIndex)
If (TblRow.Cells(3).Value.ToString = "5" Or TblRow.Cells(3).Value.ToString = "V" Then
tblRow.DefaultCellStyle.BackColor = Color.Red
ElseIf (TblRow.Cells(3).Value.ToString = "4" Or TblRow.Cells(3).Value.ToString = "B" Then
tblRow.DefaultCellStyle.BackColor = Color.Green
End If
End Sub

To iterate through the values of combo box control using vb.net

I update my question here .. Am using a combo box with no of phone numbers .I want to get the phone no one by one in a variable. Now am using the below code to get the combobox values. But still now am getting the following error message System.Data.DataRowView. Please help me to fix this error. am new for vb.net.
My partial code is here ..
For i = 0 To ComboBox1.Items.Count
Dim s As String
s = Convert.ToString(ComboBox1.Items(i))
Next i
you are using an index which is zero based.
change this:
For i = 0 To ComboBox1.Items.Count
to this:
For i = 0 To ComboBox1.Items.Count - 1
This also works!
Dim stgTest = "Some Text"
Dim blnItemMatched As Boolean = False
'-- Loop through combobox list to see if the text matches
Dim i As Integer = 0
For i = 0 To Me.Items.Count - 1
If Me.GetItemText(Me.Items(i)) = stgTest Then
blnItemMatched = True
Exit For
End If
Next i
If blnItemMatched = False Then
Dim stgPrompt As String = "You entered '" & stgTypedValue & "', which is not in the list."
MessageBox.Show(stgPrompt, "Incorrect Entry", MessageBoxButtons.OK, MessageBoxIcon.Information)
Me.Text = ""
Me.Focus()
End If
Your problem probably happens here:
s = Convert.ToString(ComboBox1.Items(i))
This doesn't return the value. It returns a string representation of the object at the given index, which in your case apparently is of type System.Data.DataRowView.
You would have to cast ComboBox1.Items(i) to the approbriate type and access its Value. Or, since its a DataRowView, you can access the values throgh the appropriate column names:
Dim row = CType(ComboBox1.Items(i), System.Data.DataRowView)
s = row.Item("column_name")
Nevertheless, first of all you should definitely close and dispose the connection, no matter whether the transaction fails or succeeds. This can be done in a finally block (option 1) or with a using statement (option 2).
Option 1
// ...
con1 = New MySqlConnection(str)
con1.Open()
Try
// ...
Catch ex As Exception
Lblmsg.Text = " Error in data insertion process....." + ex.Message
Finally
con1.Close()
con1.Dispose()
End Try
Option 2
// ...
Using con1 as New MySqlConnection(str)
con1.Open()
Try
// ...
Catch ex As Exception
Lblmsg.Text = " Error in data insertion process....." + ex.Message
Finally
con1.Close()
End Try
End using
Even after long time back you will achieve this with simply by following
For Each item As Object In combx.Items
readercollection.Add(item.ToString)
Next
Please try this
For j As Integer = 0 To CboCompany.Items.Count - 1
Dim obj As DataRowView = CboCompany.Items(j)
Dim xx = obj.Row(0)
If xx = "COMP01" Then
CboCompany.SelectedIndex = j
Exit For
End If
Next
I could not find this answer online in its entirety but pieced it together. In the snippet below cbox is a ComboBox control that has the DisplayMember and ValueMember properties initialized.
Dim itemIE As IEnumerator = cbox.Items.GetEnumerator
itemIE.Reset()
Dim thisItem As DataRowView
While itemIE.MoveNext()
thisItem = CType(itemIE.Current(), DataRowView)
Dim valueMember As Object = thisItem.Row.ItemArray(0)
Dim displayMember As Object = thisItem.Row.ItemArray(1)
' Insert code to process this element of the collection.
End While