Multithreading Safe Calls not populating comboboxes vb.net - vb.net

just curious on what im doing wrong here, the principle should work. Can anyone give me a hand?
The Code runs fine, but seems to not add them into my comboboxes
normal thread start like so
t1 = New Thread(New ThreadStart(AddressOf GetNewClientData))
t1.Start()
data is not empty or null... :)
Function GetNewClientData()
Try
Dim con As New SqlConnection
Dim myConString As String = My.Settings.ConString
Dim objcommand As SqlCommand = New SqlCommand
With objcommand
.Connection = con
Dim cmdText As String = "SELECT distinct Applicant,Client,Market,Project from AAClient order by Client"
.CommandText = cmdText
End With
con.ConnectionString = myConString
con.Open()
Using readerObj As SqlClient.SqlDataReader = objcommand.ExecuteReader
'This will loop through all returned records
While readerObj.Read
addClientInvoke(readerObj("Client").ToString)
addApplicantInvoke(readerObj("Client").ToString)
addMarketInvoke(readerObj("Client").ToString)
addProjectInvoke(readerObj("Client").ToString)
End While
End Using
con.Close()
Catch ex As Exception
End Try
Return Nothing
End Function
Delegate Sub addApplicant(s As String)
Sub addApplicantInvoke(ByVal s As String)
If CreateNewSite.cbApplicant.InvokeRequired Then
Dim d As New addApplicant(AddressOf addApplicantInvoke)
CreateNewSite.cbApplicant.Invoke(d, New Object() {s})
Else
CreateNewSite.cbApplicant.Items.Add(s)
End If
End Sub
Delegate Sub addClient(s As String)
Sub addClientInvoke(ByVal s As String)
If CreateNewSite.cbClient.InvokeRequired Then
Dim d As New addClient(AddressOf addClientInvoke)
CreateNewSite.cbClient.Invoke(d, New Object() {s})
Else
CreateNewSite.cbClient.Items.Add(s)
End If
End Sub
Delegate Sub addMarket(s As String)
Sub addMarketInvoke(ByVal s As String)
If CreateNewSite.cbMarket.InvokeRequired Then
Dim d As New addMarket(AddressOf addMarketInvoke)
CreateNewSite.cbMarket.Invoke(d, New Object() {s})
Else
CreateNewSite.cbMarket.Items.Add(s)
End If
End Sub
Delegate Sub addProject(s As String)
Sub addProjectInvoke(ByVal s As String)
If CreateNewSite.cbProject.InvokeRequired Then
Dim d As New addProject(AddressOf addProjectInvoke)
CreateNewSite.cbProject.Invoke(d, New Object() {s})
Else
CreateNewSite.cbProject.Items.Add(s)
End If
End Sub
possibly how i'm calling the delegate??
any help is appreciated
**** thanks to #jods here is the working code with one of the invoke methods****
starting thread in another modul
t1 = New Thread(New ParameterizedThreadStart(AddressOf GetNewClientData))
t1.Start(Me)
Code within the Modul
Function GetNewClientData(ByVal oldForm As CreateNewSite)
Try
Dim con As New SqlConnection
Dim myConString As String = My.Settings.ConString
Dim objcommand As SqlCommand = New SqlCommand
With objcommand
.Connection = con
Dim cmdText As String = "SELECT distinct Applicant,Client,Market,Project from AAClient order by Client"
.CommandText = cmdText
End With
con.ConnectionString = myConString
con.Open()
Using readerObj As SqlClient.SqlDataReader = objcommand.ExecuteReader
'This will loop through all returned records
While readerObj.Read
addApplicantInvoke(readerObj("Applicant").ToString, oldForm)
addClientInvoke(readerObj("Client").ToString)
addMarketInvoke(readerObj("Market").ToString)
addProjectInvoke(readerObj("Project").ToString)
End While
End Using
con.Close()
Catch ex As Exception
MsgBox(ex)
End Try
Return Nothing
End Function
Delegate Sub addApplicant(s As String, oldform As CreateNewSite)
Sub addApplicantInvoke(ByVal s As String, ByVal oldform As CreateNewSite)
If oldform.InvokeRequired Then
Dim d As New addApplicant(AddressOf addApplicantInvoke)
oldform.cbApplicant.Invoke(d, New Object() {s, oldform})
Else
oldform.cbApplicant.Items.Add(s)
End If
End Sub

The problem is CreateNewSite.cbProject. CreateNewSite is not your form instance. It's a nifty :p VB.NET feature called the default form instance:
VB has a concept of "Default Form Instances". For every Form in the application's namespace, there will be a default instance created in the My namespace under the Forms property.
You need to pass the correct form instance (i.e. 'Me' / 'this') to your background thread.

Related

How to make your displayed data vary once this form pops up again?

I am new to VB.net and I really had a hard time to this problem. I want to fetch all rows where the statement is "Logical Reasoning" by displaying it one by one in my richtextbox and radio buttons once this form show up again through next button. I am using xampp for my database and visual studio vb.net. I hope you can help me with this. Thank you in advance. Here is my code in my database connection module:
Private dbConn As New MySqlConnection("datasource=localhost;port=3306;username=root;password=;database=quiz;Convert Zero DateTime=True")
Private qreader As MySqlDataReader
Private cmd As MySqlCommand = New MySqlCommand
Public Sub displayData(ByRef richText As RichTextBox, ByRef radiobtnA As RadioButton, ByRef radiobtnB As RadioButton, ByRef radiobtnC As RadioButton, ByRef radiobtnD As RadioButton, ByRef sql As String)
Try
cmd.Connection = dbConn
openConnection()
cmd.CommandText = sql
qreader = cmd.ExecuteReader(CommandBehavior.CloseConnection)
While qreader.Read
richText.Text = (qreader("Question").ToString)
radiobtnA.Text = (qreader("Choice A").ToString)
radiobtnB.Text = (qreader("Choice B").ToString)
radiobtnC.Text = (qreader("Choice C").ToString)
radiobtnD.Text = (qreader("Choice D").ToString)
End While
Catch ex As Exception
MsgBox(ex.Message, MsgBoxStyle.Critical, "Error")
End Try
qreader.Close()
closeConnection()
End Sub
ReadOnly Property getConnection() As MySqlConnection
Get
Return dbConn
End Get
End Property
Sub openConnection()
If dbConn.State = ConnectionState.Closed Then
dbConn.Open()
End If
End Sub
Sub closeConnection()
If dbConn.State = ConnectionState.Open Then
dbConn.Close()
End If
End Sub
End Module ```
Here is the code in my form that I want to display the data with:
```Public Class quizForm
Dim sql As String
Private Sub quizForm_Load(sender As Object, e As EventArgs) Handles MyBase.Load
sql = "SELECT * FROM `examquestion` WHERE `Exam Category` = 'Logical Reasoning'"
displayData(rtxtQuestion, rbnA, rbnB, rbnC, rbnD, sql)
End Sub```
The code is working but only displayed the first row of category Logical Reasoning.

Having issues when 2 users are working with the same program

Public Class DataAccess
Dim dataAcc As New DataAccess
Public Shared dtx As New DataTable
Private Shared ConStr As String = "Server = 10.18.206.30;database=PeajeFacturacion;User ID=FacturacionUsr;Password = ukShLq?U6&hNxDxN+67!XaYq"
Public Shared Function AddOneRecord(PK As String) As DataTable
Using cn As New SqlConnection(ConStr),
cmd As New SqlCommand("Select c.idCruce, c.FechaCruce, c.HoraCruce, c.claseVehiculo, c.Importe,
c.codigoCobro, n.nomCaseta
from dbo.Cruce AS c
JOIN dbo.nombre_caseta AS n
ON n.numCaseta=c.ClavePlaza
where c.CodigoCobro = #PK;", cn)
cmd.Parameters.Add("#PK", SqlDbType.VarChar).Value = PK
cn.Open()
dtx.Load(cmd.ExecuteReader)
End Using
Return dtx
End Function
End Class
I use that part to create the connection just like the example #Mary posted. Then:
Protected Sub btnAgregar_Click(sender As Object, e As EventArgs) Handles btnAgregar.ServerClick
Dim numTicket As String = txtNoTicket.Text
Dim dtx As New DataTable
Dim pk As String
pk = txtNoTicket.Text
Dim con2 As New SqlConnection
Dim cmd2 As New SqlCommand
Dim dr As SqlDataReader
Dim dtx2 As DataTable
Dim status As Boolean = False
'If Not Integer.TryParse(ticket.Text, pk) Then
If String.IsNullOrEmpty(pk) Then
'ScriptManager.RegisterStartupScript(Me, Page.GetType, "Script", "showDisplay();", True)
cFunciones.mostrarDivAlertaAA("Type a number", "dangerNormal", Me.Page, "")
Else
dtx = DataAccess.AddOneRecord(pk)
So when adding tickets the issue is the ticket 1 user adds, gets added to the other user even though they use different sessions and different computers. The program is in test fase right now.
You can get rid of Shared in the DatAccess class. Then each instance of the class will have its own data. Now you must declare an instance of the class and call the method on that instance.
Public Class DataAccess
Dim dataAcc As New DataAccess
Public dtx As New DataTable
Private ConStr As String = "Server = 10.18.206.30;database=PeajeFacturacion;User ID=FacturacionUsr;Password = ukShLq?U6&hNxDxN+67!XaYq"
Public Function AddOneRecord(PK As String) As DataTable
Using cn As New SqlConnection(ConStr),
cmd As New SqlCommand("Select c.idCruce, c.FechaCruce, c.HoraCruce, c.claseVehiculo, c.Importe,
c.codigoCobro, n.nomCaseta
from dbo.Cruce AS c
JOIN dbo.nombre_caseta AS n
ON n.numCaseta=c.ClavePlaza
where c.CodigoCobro = #PK;", cn)
cmd.Parameters.Add("#PK", SqlDbType.VarChar).Value = PK
cn.Open()
dtx.Load(cmd.ExecuteReader)
End Using
Return dtx
End Function
End Class
Protected Sub btnAgregar_Click(sender As Object, e As EventArgs) Handles btnAgregar.ServerClick
Dim dtx As New DataTable
Dim pk = txtNoTicket.Text
If String.IsNullOrEmpty(pk) Then
cFunciones.mostrarDivAlertaAA("Type a number", "dangerNormal", Me.Page, "")
Else
Dim datAcc As New DataAccess
dtx = datAcc.AddOneRecord(pk)
End If
End Sub

Do I need to dispose an instance of my custom class to free up memory? Then how? VB.NET

I just want to save time and codes to create a custom class in executing my SQL queries so I created just like this:
Imports ADODB
Public Class MySQLConnection
Private SQLConnection As ADODB.Connection
Private SQLConnectionString As String = "Provider=SQLOLEDB;Data Source=111.111.10.201;Initial Catalog=dbSample;User ID=User;password=123456;"
Private SQLRecordSet As ADODB.Recordset
Public Recordset As ADODB.Recordset
Public Message As String
Public Function ExecuteSQLQuery(vQuery As String) As Boolean
Try
SQLConnection.Open(SQLConnectionString)
SQLRecordSet.CursorLocation = ADODB.CursorLocationEnum.adUseClient
SQLRecordSet.CursorType = ADODB.CursorTypeEnum.adOpenStatic
SQLRecordSet.LockType = ADODB.LockTypeEnum.adLockBatchOptimistic
SQLRecordSet.Open(vQuery, SQLConnection)
Recordset = SQLRecordSet 'passing the content of recordset to a public recordset for later use in my main program.
SQLRecordSet.Close()
SQLConnection.Close()
Message = "Query executed successfully."
Return True
Catch ex As Exception
Message = ex.Message
Return False
End Try
End Function
End Class
QUESTION #1
But since I will be creating multiple instance of this class throughout my program, do I need to somehow dispose the instance to free up the memory immediately after use?
Whenever I need to execute my query, I use my code below in my main program:
Private Sub COnnectToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles COnnectToolStripMenuItem.Click
Dim DB_CONN As New MySQLConnection
If DB_CONN.ExecuteSQLQuery("SELECT * FROM tbl_Stores") Then
If DB_CONN.Recordset.RecordCount <> 0 Then
DB_CONN.Recordset.MoveFirst()
Do While Not DB_CONN.Recordset.EOF
'Read each record here
DB_CONN.Recordset.MoveNext()
Loop
End If
DB_CONN.Recordset.Close()
'==============================
'This is where I think I should dispose my class instance [DB_CON].
MsgBox("MESSAGE: " & DB_CONN.Message)
Else
MsgBox("ERROR: " & DB_CONN.Message)
End If
End Sub
QUESTION #2:
How do I dispose the instance of my class after use?
I just want to know this so I can clean up my previous programs.
All I find in Google is for C++ so I'm not sure if it works for VB.Net
Please help! :(
If I were you I'd look at making the ExecuteSQLQuery completely self contained such that it takes an Action(Of ADODB.Recordset). Then it can clean up after itself immediately after it has executed.
I'd initially write it like this:
Public Module MySQLConnection
Private SQLConnectionString As String = "Provider=SQLOLEDB;Data Source=111.111.10.201;Initial Catalog=dbSample;User ID=User;password=123456;"
Public Function ExecuteSQLQuery(vQuery As String, process As Action(Of ADODB.Recordset), message As Action(Of String)) As Boolean
Try
Dim conn As ADODB.Connection = New ADODB.Connection()
conn.Open(SQLConnectionString)
Dim rs As ADODB.Recordset = New ADODB.Recordset()
rs.CursorLocation = ADODB.CursorLocationEnum.adUseClient
rs.CursorType = ADODB.CursorTypeEnum.adOpenStatic
rs.LockType = ADODB.LockTypeEnum.adLockBatchOptimistic
rs.Open(vQuery, conn)
process?(rs)
rs.Close()
conn.Close()
message?("Query executed successfully.")
Return True
Catch ex As Exception
message?(ex.Message)
Return False
End Try
End Function
End Module
Now you'd use it like this:
Private Sub COnnectToolStripMenuItem_Click2(sender As Object, e As EventArgs) Handles COnnectToolStripMenuItem.Click
Dim success As Boolean = MySQLConnection.ExecuteSQLQuery("SELECT * FROM tbl_Stores",
Sub(recordset)
If recordset.RecordCount <> 0 Then
recordset.MoveFirst()
Do While recordset.EOF
'Read each record here
recordset.MoveNext()
Loop
End If
End Sub, AddressOf MsgBox)
End Sub
Or even better - make the method return an enumerable of some value:
Public Module MySQLConnection
Private SQLConnectionString As String = "Provider=SQLOLEDB;Data Source=111.111.10.201;Initial Catalog=dbSample;User ID=User;password=123456;"
Public Iterator Function ExecuteSQLQuery2(Of T)(vQuery As String, process As Func(Of ADODB.Recordset, T)) As IEnumerable(Of T)
Dim conn As ADODB.Connection = New ADODB.Connection()
conn.Open(SQLConnectionString)
Dim rs As ADODB.Recordset = New ADODB.Recordset()
rs.CursorLocation = ADODB.CursorLocationEnum.adUseClient
rs.CursorType = ADODB.CursorTypeEnum.adOpenStatic
rs.LockType = ADODB.LockTypeEnum.adLockBatchOptimistic
rs.Open(vQuery, conn)
If rs.RecordCount <> 0 Then
rs.MoveFirst()
Do While rs.EOF
Yield process(rs)
rs.MoveNext()
Loop
End If
rs.Close()
conn.Close()
End Function
End Module
Then you can do this:
Private Sub COnnectToolStripMenuItem_Click2(sender As Object, e As EventArgs) Handles COnnectToolStripMenuItem.Click
Dim values As IEnumerable(Of Integer) = MySQLConnection.ExecuteSQLQuery2(Of Integer)("SELECT * FROM tbl_Stores", Function(recordset) CType(recordset.Fields("Value").Value, Integer))
End Sub

The ConnectionString property has not been initialized error with VB.NET

I am trying to fill a datagrid with data from access, but every time I run this program i get an error saying ConnectionString property has not been initialized i have tried everything i know. Can someone please help
Private Sub RefreshData()
cnn = New OleDb.OleDbConnection
cnn.ConnectionString = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=|DataDirectory|\My_db.accdb"
If Not cnn.State = ConnectionState.Open Then
' open connection '
cnn.Open()
End If
Dim da As New OleDb.OleDbDataAdapter()
Dim dt As New DataTable
'fill datatable'
da.Fill(dt)
Me.DataGridView1.DataSource = dt
' close connection'
cnn.Close()
End Sub
Private Sub BindGrid()
If Not cnn.State = ConnectionState.Open Then
' open connection '
cnn.Open()
End If
Dim cmd As New OleDb.OleDbCommand
cmd.Connection = cnn
cmd.CommandText = "SELECT * FROM Training log WHERE Runner Name='" & Profile.UsernameTextBox.Text & "'"
cmd.ExecuteNonQuery()
Me.RefreshData()
cnn.Close()
End Sub
It looks like the OleDbCommand is never set to use the OleDbConnection object, and the DataAdapter is never set to use the command. Try this, which also fixes several other items that do not conform to commonly accepted practice:
'Put this module in a separate file
'Any and *ALL* code that talks directly to the DB should go in this module, and use the style of the RefreshData() method below.
Public Module DataLayer
Private Property ConnectionString() As String
Get
Return "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=|DataDirectory|\My_db.accdb"
End Get
End Property
'I left the name alone so you could match it up to your original code,
' but a better name would be something like "TrainingLogByRunner()"
Public Function RefreshData(ByVal RunnerName As String) As DataTable
Dim dt As New DataTable
Using cnn As New OleDb.OleDbConnection(ConnectionString), _
cmd As New OleDb.OleDbCommand("SELECT * FROM [Training log] WHERE [Runner Name]= ?", cnn), _
da As new OleDb.OleDbDataAdapter(cmd)
'**NEVER** use string concatentation to substitute this kind of value into a query!
'Had to guess at column type/length here
cmd.Parameters.Add("?", OleDbType.VarWChar, 40).Value = RunnerName
'No need to call Open() for the connection...
' the DataAdapter.Fill() method will manage opening/closing the connection
da.Fill(dt)
End Using
Return dt
End Function
End Module
Private Sub BindGrid()
Me.DataGridView1.DataSource = DataLayer.RefreshData(Profile.UsernameTextBox.Text)
End Sub

SQLite Query is not working properly - can't load datatable

I am trying to write a function that queries the sqlite db I have. For some reason it does not work properly. Below are the supporting functions that I am using. I can get it to add tables perfectly fine.
Private Sub GetSqlConnection()
Me.SQLConnectionString = New SQLiteConnectionStringBuilder
Me.SQLConnectionString.DataSource = Path.Combine(Application.StartupPath, "mydb.sqlite")
Me.SQLConnectionString.Version = 3
SQLConnection = New SQLiteConnection(Me.SQLConnectionString.ConnectionString)
End Sub
Private Sub Query(ByVal SQLString As String)
Try
Dim SQLiteDRObj As SQLiteDataReader
Dim ResultsTableObj As DataTable = Nothing
Dim ResultSet As DataSet = Nothing
Dim SQLAdapter As SQLiteDataAdapter = Nothing
Me.GetSqlConnection()
SQLConnection.Open()
SQLCommand = New SQLiteCommand(SQLConnection)
SQLCommand.CommandText = SQLString
SQLiteDRObj = SQLCommand.ExecuteReader()
ResultsTableObj.Load(SQLiteDRObj)
SQLiteDRObj.Close()
SQLConnection.Close()
SQLConnection.Dispose()
Catch ex As Exception
MessageBox.Show(ex.Message)
End Try
End Sub
object shows as filled http://josephberardi.com/stackoverflow/objfilled.png
object shows as filled http://josephberardi.com/stackoverflow/exception.png
ResultsTableObj is Nothing when you call the Load method
Change this line to
Private Sub Query(ByVal SQLString As String)
Try
....
Dim ResultsTableObj As DataTable = New DataTable()
....