error occured when clicking a programatically added button [duplicate] - vb.net

This question already has answers here:
What is a NullReferenceException, and how do I fix it?
(27 answers)
Closed 5 years ago.
I am trying to programatically generate buttons and add event handlers to them and i've succeeded in creating the buttons but when I click on one of the I get the following message object reference not set to an instance of an object .
Here is the code that creates the buttons:
Dim i As Integer = 1
For Each dtab As DataTable In ds.Tables
For Each drow As DataRow In dtab.Rows
If (CInt(drow(3)) < CInt(drow(4))) Then
Dim l As New Label()
With l
.Location = New System.Drawing.Point(30, 40 * i)
.Text = "product number " & drow(0) & " has reached the minimal quantity"
.Width = 300
Panel3.Controls.Add(l)
End With
Dim b As New Button()
With b
.Location = New System.Drawing.Point(350, 40 * i)
.Enabled = True
.Width = 100
.Text = "fill stock"
Panel3.Controls.Add(b)
AddHandler b.Click, AddressOf Me.Button_Click
End With
i = i + 1
End If
Next
Next
the code that handels the button click is the following:
Private Sub Button_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)
Dim co As New SqlConnection("server=JAMMINGJACK-PC\SQLEXPRESS ;initial catalog=td3;integrated security=true;")
Try
Dim cmd As New SqlCommand
co.Open()
cmd.Connection = co
cmd.CommandText = "Update article set qteStck=(qteStck+(seuilmin*3)) where numart=" & drow(0) '
cmd.CommandType = CommandType.Text
cmd.ExecuteNonQuery()
co.Close()
Catch ex As Exception
MsgBox(ex.Message, MsgBoxStyle.Critical, Me.Text)
End Try
End Sub

There are two big problems on this line in your event handler:
cmd.CommandText = "Update article set qteStck=(qteStck+(seuilmin*3)) where numart=" & drow(0) '
The first problem is the code is crazy vulnerable to sql injection attacks. It's a side-issue to the question, but this is IMPORTANT, and you should take a few minutes to Google parameterized queries and how to use them.
The second problem is with the drow(0) expression. That variable has no meaning in this method. It was scoped to the For Each loop in the code that created your buttons, but it has no meaning at all here. That this compiles at all means you either tried to re-declare it at the class level (which won't help; that will be a different drow variable) or turned Option Strict off, which is very poor practice.
There are several ways you can address this, such as encoding the drow(0) value in theTag property or inferring it from the Name. My preferred approach here would be to create a custom control that groups your label and button together.

Related

VB.net update SQL command

For some reason I cannot get my record to update. Here goes:
I have a Windows form, that will upon loading display the current status of an aircraft. If that status changes I can select the value from a combobox (cboServ). When I click the Exit button from that form the status should update, so upon loading the form again the new value appears. However it doesn't.
This is what I have currently as the code:
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim updateQuery As String = "UPDATE dbo.aircraft SET dbo.aircraft.condition = #OE_status WHERE aircraft.avNum = 'ab201'"
Dim updateCmd As New SqlCommand(updateQuery, con)
updateCmd.Parameters.Add("#OE_status", cboServ.SelectedValue)
MessageBox.Show("it worked")
con.Close()
Me.Close()
Form1.Show()
End Sub
The error I get back is - which I don't fully understand:
System.InvalidCastException: 'Conversion from type 'DataRowView' to type 'String' is not valid.'
This comes from the line reading cboServ.SelectedValue.
There is more than one problem with the code as shown.
First, you should use Option Strict On to make sure that the types of all the variables used match up properly.
You can isolate the problem more easily by separating the things being done in the button click handler out into other methods. For example, we could put the database interaction into its own method:
Sub UpdateAircraftCondition(avNum As String, condition As String)
Dim connStr = "YOUR CONNECTION STRING HERE"
Dim updateQuery As String = "UPDATE dbo.aircraft SET dbo.aircraft.condition = #OE_status WHERE aircraft.avNum = #AvNum"
Using conn As New SqlConnection(connStr)
Using cmd As New SqlCommand(updateQuery, conn)
cmd.Parameters.Add(New SqlParameter With {.ParameterName = "#AvNum", .SqlDbType = SqlDbType.NVarChar, .Size = 16, .Value = avNum})
cmd.Parameters.Add(New SqlParameter With {.ParameterName = "#OE_Status", .SqlDbType = SqlDbType.NVarChar, .Size = 16, .Value = condition})
conn.Open()
cmd.ExecuteNonQuery()
conn.Close()
End Using
End Using
End Sub
(You will need to make the Size (for string data) and SqlDbType match up to the columns in the database.)
Notice how the connection only exists where it is needed - the Using construct takes care of disposing of unmanaged resources (like the SqlConnection) to keep memory tidied up and not leaking.
Instead of putting the actual connection string in everywhere, which makes it a lot of hassle to change it, it is normal to put it in some settings file, for example by using My.Settings.
According to the error message, cboServ.SelectedValue is a DataRowView, not a String. Which makes me wonder if cboServ is not a ComboBox. But we can get a useful error message by trying the following code for the button click event handler:
Private Sub bnUpdateCondition_Click(sender As Object, e As EventArgs) Handles bnUpdateCondition.Click
If cboServ.SelectedIndex >= 0 Then
Dim aircraftCondition = cboServ.SelectedItem.ToString()
Dim avNum = "ab201"
UpdateAircraftCondition(avNum, aircraftCondition)
' more code may go here
End If
End Sub
Please note that I tried to give the button a meaningful name: doing that will make it much easier for you in the future than trying to figure out what "Button337" is for.
Change the row:
updateCmd.Parameters.Add("#OE_status", cboServ.SelectedValue)
to:
updateCmd.Parameters.AddWithValue("#OE_status", cboServ.SelectedValue.ToString())
or you can use a explicit cast:
var dataRowView = cboServ.SelectedValue as DataRowView;
var row = dataRowView.row As MyDataTableDefinition;
updateCmd.Parameters.AddWithValue("#OE_status", row[“OE_status”].ToString())

Duplicate bindings error when trying to go to next row in DB

I am new to this whole binding thing but basically when i press next button on my form it is meant to scroll through my database displaying each row but the code i will supply below is just a temp as i want to make sure it all works before adding more code to it.
When i load the section i have it so it preloads the first row into my form so when you press next it will bring you to row 2 and next again will bring you to row 3 etc but when i hit next to go to row 3 from row 2 i receive the error: This causes two bindings in the collection to bind to the same property.
Code:
Private Sub click()
sql = "Select * from tbl"
Using dbcon As New OleDbConnection(ACEConnStr)
Using cmd As New OleDbCommand(sql, dbcon)
dbcon.Open()
dtSample = New DataTable
dtSample.Load(cmd.ExecuteReader)
End Using
End Using
' initialize BS from DT
bsSample = New BindingSource(dtSample, Nothing)
TxtCI.DataBindings.Add("Text", bsSample, "CustomerID")
End Sub
Next button:
Private Sub BtnNext_Click(sender As Object, e As EventArgs) Handles BtnNext.Click
click()
DataBindings.Clear()
bsSample.MoveNext()
BtnNext.Enabled = (bsSample.Count - 1 > bsSample.Position)
End Sub
This code block:
Private Sub nclick()
sql = "Select * from tblcustomer"
Using dbcon As New OleDbConnection(ACEConnStr)
Using cmd As New OleDbCommand(sql, dbcon)
dbcon.Open()
dtSample = New DataTable
dtSample.Load(cmd.ExecuteReader)
End Using
End Using
' initialize BS from DT
bsSample = New BindingSource(dtSample, Nothing)
TxtCI.DataBindings.Add("Text", bsSample, "CustomerID")
TxtName.DataBindings.Add("Text", bsSample, "Title")
ChkSales.DataBindings.Add("Checked", bsSample, "SalesCustomer")
End Sub
...needs to run once, but only once. Move the whole lot of it to the form load. Then:
Private Sub BtnNext_Click...
bsSample.MoveNext()
BtnNext.Enabled = (bsSample.Count - 1 > bsSample.Position)
End Sub
I am not sure if this is a Find dialog or what, but it should be noted that the DataTable for all customers can have application-wide uses - such as checking if customer #30 exists before trying to delete them.

Controls not showing while loading form

I am trying to Load the form as
Dim f as New Form2
f.show()
The form is getting loaded but it doesnt show all the controls. I have two buttons and two text box. Both the buttons and one text box appears as transparent. The form appears like that till the current subroutine has ended.
Moreover, the form on loading shall display the text fetched from database and shall display the text (fetched again at equal interval from db) unless user explicitly closes the application. That logic also is in Form2_Load event.
How do I write the logic such that form2 displays properly and gets the text from db at regular interval.
I am creating a dictionary like application for healthcare domain. It works in two mode. One of the mode is ribbon mode, where a form is created (the form is marked as topmost) which should display the term and definition as long as application is alive. Hence you see an endless loop. Once user presses the close button or presses X, the application will close.
I was playing around with the code and moved it from Load even to shown event. However the issue persists.
Private Sub Form2_Shown(ByVal sender As Object, ByVal e As EventArgs) _
Handles MyBase.Shown
Dim myConnection As OleDbConnection = New OleDbConnection
Dim idSelected, queryGetWordDef, totalRows
Dim rowReturned, queryGetMaxID, provider, ipath, dataFile, connString As String
Dim dict() As String
Dim dr1 As OleDbDataReader
Dim dt As DataTable = New DataTable
provider = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source ="
ipath = Application.StartupPath
dataFile = ipath & "\Database\database1.mdb" ' Change it to your Access Database location
connString = provider & dataFile
myConnection.ConnectionString = connString
queryGetMaxID = "SELECT ID FROM Table1"
myConnection.Open()
Dim cmd As OleDbCommand = New OleDbCommand(queryGetMaxID, myConnection)
Try
dr1 = cmd.ExecuteReader()
Catch ex As Exception
Console.WriteLine(ex.Message)
End Try
dt.Load(dr1)
totalRows = dt.Rows.Count
While True
idSelected = dt.Rows.Item(CInt(totalRows * Rnd()) + 1)(0)
queryGetWordDef = "SELECT Word & ""#"" & Meaning FROM Table1 WHERE ID = " & CStr(idSelected)
cmd = New OleDbCommand(queryGetWordDef, myConnection)
Try
rowReturned = cmd.ExecuteScalar()
Catch ex As Exception
Console.WriteLine(ex.Message)
End Try
dict = rowReturned.Split("#")
Me.txtBoxDefinition.Text = dict(1)
Me.txtBoxTerm.Text = dict(0)
Thread.Sleep(5000)
End While
End Sub
Picture of form attached for more clarity.
As mentioned, you have an infinite loop. The loop is entered before the form is completed being created.
To achieve what you are requesting you need to look at backgroundworker
You can use this in conjunction with the timer to trigger the backgrounderworker doWork() event.
The link also has an example of how to update the text on a form as well.
You have an endless loop in your Shown event handler. That code is executed on the UI thread and it never ends, so you can never do anything else on the UI thread.
Get rid of that loop altogether. If you want to do something every 5 seconds then use a Timer with an Interval of 5000.

combobox doesn't return any text in vb.net

I have a function that get 3 argument , a textbox and 2 combobox and use them in the code as temp of a OleDbDataReader but I have a problem and take runtime
error: No value given for one or more required parameters.
Sub load_txt_code(ByVal nkala As ComboBox, ByVal ckala As ComboBox, ByVal ghyemat As TextBox)
dr.Close()
cmd.Connection = con
cmd.CommandText = "select name_jens from ajnas where id = " & nkala.Text & ""
dr = cmd.ExecuteReader()
While dr.Read
nkala.Text = dr.Item(0)
End While
'por kardane combobox e gheymat
dr.Close()
cmd.CommandText = "select gheymate_forush from ajnas where id = " & ckala.Text & ""
dr = cmd.ExecuteReader()
While dr.Read
If Not IsDBNull(dr.Item(0)) Then
ghyemat.Text = dr.Item(0)
Else
ghyemat.Text = Nothing
End If
End While
End Sub
add a breakpoint in the gheymat.text = dr.item(0) to see if it ever goes there.
Your code makes it possible that your text is overwritten if field 0 has a value and field 1 has none.
It will read field (1) and then overwrite the text you set wiht dr.item(0) before. So you should add an "end while" behind gheymat.text = dr.item(0) - if your code ever goes there. If this is not enough to tackle it, add an early breakpoint and F10 trough it all, then you can see if your query generates any data in the first place.

Why is ListView not refreshing?

Hi I am inserting into a table then reading everything back into a ListView When I re-open the program I see the data I just saved in my ListView, but this record is not showing in my ListView at the time of saving (although it is saved in the table).
I am using
listView.Update()
as well as
listView.Refresh()
but it does not seem to work. I am just using a SELECT query to read data off the datareader and store it in my listView as follows (which is working properly)
The only problem is that the listView is not refreshing immediately, but it works when I close/open the program
here's the code I am using at the end of my Save method. basically these two methods get called
Private Sub SetColumns()
Dim lstpenalty As New ListView()
lstpenalty.Items.Clear()
lstpenalty.Visible = True
lstpenalty.Bounds = New Rectangle(New Point(390, 55), New Size(560, 379))
lstpenalty.Name = "lstpenalty"
lstpenalty.FullRowSelect = True
lstpenalty.View = View.Details
lstpenalty.GridLines = True
lstpenalty.Items.Clear()
lstpenalty.Columns.Add("a", 75)
lstpenalty.Columns.Add("b", 70)
lstpenalty.Columns.Add("c", 105)
lstpenalty.Columns.Add("d", 98)
lstpenalty.Columns.Add("e", 90)
lstpenalty.Columns.Add("f", 105)
Me.Controls.Add(lstpenalty)
LoadPenaltyList(lstpenalty)
End Sub
Private Sub LoadPenaltyList(ByRef listView As ListView)
Dim gDR As OracleDataReader
Dim cmd As New OracleCommand
Dim lstpenaltyview As New ListViewItem
Try
cnn.Connect_to_Oper_Agent()
cmd.Connection = cnn.cnn
listView.Items.Clear()
cmd.CommandText = " select a," & _
"b, " & _
"c, " & _
"d," & _
"e," & _
"f" & _
" FROM myTable" & _
" commit"
gDR = cmd.ExecuteReader()
While gDR.Read
lstpenaltyview = listView.Items.Add(Null_To_String(gDR("a")))
lstpenaltyview.SubItems.Add(gDR("b"))
lstpenaltyview.SubItems.Add(gDR("c"))
lstpenaltyview.SubItems.Add(gDR("d"))
lstpenaltyview.SubItems.Add(gDR("e"))
lstpenaltyview.SubItems.Add(gDR("f"))
End While
listView.Update()
Catch ex As Exception
MsgBox("There was an error... -> " & ex.ToString)
Finally
cmd.Dispose()
cnn.Close_Conn()
End Try
End Sub
Thanks for your help
It is worth looking at what methods do.
http://msdn.microsoft.com/en-us/library/system.windows.forms.listview_methods%28v=vs.71%29.aspx
Update : Causes the control to redraw the invalidated regions within its client area.
Refresh: Forces the control to invalidate its client area and immediately redraw itself and any child controls.
To update it using table info, first Clear the listview, then redo the process you used to initially populate it.
So I was creating the ListView dynamically. The issue was that it kept creating ListViews over each other (memory leak), and it always showed the previous one. I created a static viewList versus a dynamic one and the issue is resolved:D
Use
For Each i As Windows.Forms.ListViewItem In ListView1.Items
i.Remove()
Next
Instead of Clear