VB.NET Backgroundworker only show loading form once? - vb.net

I have a button on a form which basically get data from my database as below.
Private Sub ToolStripButton1_Click(sender As Object, e As EventArgs)
Handles ToolStripButton1.Click
BackgroundWorker1.RunWorkerAsync()
Loading_Screen.ShowDialog()
End Sub
The loading screen is called after my code (obtain data from database) is run in backgroundworker.
When backgroundworker is done, I close the loading form as below
Private Sub BackgroundWorker1_RunWorkerCompleted(sender As Object, e As RunWorkerCompletedEventArgs)
Handles BackgroundWorker1.RunWorkerCompleted
DataGridView1.DataSource = bSource
SDA.Update(dataTable)
ToolStripLabel1.Text = "RESULT : " + DataGridView1.RowCount.ToString
Loading_Screen.Close()
End Sub
This only works when I started the application for the first time. Whenever I click the button again, the loading form will not show anymore but the code still runs fine. Any idea?
The loading form has no code at all, just a running progress bar every time it is loaded.
What I have done but no luck :
Me.Refresh() the main form after calling loading form.
Me.Refresh() the loading form when on load function.
Tried loadingform.hide() instead of show()
Tried both show() and showdialog()
Tried creating new instance of the loading form.
Me.dispose() loading form on closing function
Me.dispose() main form on closing function
Setting loading form as top most.
UPDATE (I will keep updating my progress here)
As many of you asked to create a new instance, here is what I already did
Private Sub ToolStripButton1_Click(sender As Object, e As EventArgs) Handles ToolStripButton1.Click
BackgroundWorker1.RunWorkerAsync()
ldScreen = New Loading_Screen()
ldScreen.ShowDialog()
Me.Refresh()
End Sub
Then, in run completed,
Private Sub BackgroundWorker1_RunWorkerCompleted(sender As Object, e As RunWorkerCompletedEventArgs) Handles BackgroundWorker1.RunWorkerCompleted
DataGridView1.DataSource = bSource
SDA.Update(dataTable)
ToolStripLabel1.Text = "RESULT : " + DataGridView1.RowCount.ToString
ldScreen.Close()
BackgroundWorker1.Dispose()
End Sub
In my loading form, the code is only this
Private Sub Loading_Screen_FormClosing(sender As Object, e As FormClosingEventArgs) Handles Me.FormClosing
Me.Dispose()
End Sub
Private Sub Loading_Screen_Load(sender As Object, e As EventArgs) Handles Me.Load
Me.Refresh()
End Sub
UPDATE 2
By stripping out most of my code and putting system thread sleep in backgroundworker do work, the loading form shows up properly. So here is my code in backgroundworkerdowork on what is actually happening.
Private Sub BackgroundWorker1_DoWork(sender As Object, e As DoWorkEventArgs) Handles BackgroundWorker1.DoWork
Connect2Database()
Try
sqlCommand.CommandText = "Select * from kup_table" 'Load full database into gridview
SDA.SelectCommand = sqlCommand
SDA.Fill(dataTable)
bSource.DataSource = dataTable
mySqlConn.Close()
Catch ex As MySqlException
MsgBox(ex.ToString)
If mySqlConn.State = ConnectionState.Open Then
mySqlConn.Close()
End If
Finally
mySqlConn.Dispose()
End Try
'System.Threading.Thread.Sleep(2000)
End Sub
And here is the Connect2Database function codes
Private Sub Connect2Database()
sqlCommand = New MySqlCommand
dataTable = New DataTable
SDA = New MySqlDataAdapter
bSource = New BindingSource
Try
dataTable.Clear()
mySqlConn.ConnectionString = connString
sqlCommand.Connection = mySqlConn
mySqlConn.Open()
Catch ex As MySqlException
MsgBox(ex.ToString)
If mySqlConn.State = ConnectionState.Open Then
mySqlConn.Close()
End If
End Try
End Sub
UPDATE 3
What I have noticed is that when my System.Threading.Thread.Sleep(2000) is not commented, the loading screen will show up normally. But if I changed it to System.Threading.Thread.Sleep(1), loading screen does not shows up. Why is this happening? Code runs super fast after the first time?

This is because calling Close() disposes the Form. So either you have to create a new instance of the form every time, or you need to use Hide(). Judging by your question, I think you want the former.

have you tried to create a new instance of the form?
Private Sub ToolStripButton1_Click(sender As Object, e As EventArgs)
Handles ToolStripButton1.Click
Dim frm As New Loading_Screen
BackgroundWorker1.RunWorkerAsync()
frm.ShowDialog()
End Sub

Related

Combo Box Declaration expected

When I got the value for the combo box from the MySQL database it seems getting error declaration expected in line 4. Can anyone help me? Here I attach my code
Imports MySql.Data.MySqlClient
Public Class Utama
Private Sub LogoutToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles LogoutToolStripMenuItem.Click
Me.Hide()
Dim utama As New Login
utama.Show()
End Sub
Private Sub KeluarToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles KeluarToolStripMenuItem.Click
Me.Close()
End Sub
Private Sub SupplierToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles SupplierToolStripMenuItem.Click
Me.Hide()
Dim supplier As New Supplier
supplier.Show()
End Sub
Private Sub ProdukToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles ProdukToolStripMenuItem.Click
Me.Hide()
Dim Produk As New Produk
Produk.Show()
End Sub
Private Sub CetakToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles CetakToolStripMenuItem.Click
Me.Hide()
Dim Cetak As New Cetak
Cetak.Show()
End Sub
Dim connection As New MySqlConnection("Server=127.0.0.1;Database=pembelian;Uid=root;Pwd=;")
Dim da As New MySqlDataAdapter("select * from supplier", connection)
Dim dt As DataTable
da.fill(dt)
ComboBox1.Datasource=dt
ComboBox1.DisplayMember = "npwp"
ComboBox1.ValueMember = "npwp"
End Class
You need to put that code inside a method. You can't just put arbitrary code anywhere in a class. The only thing that can be directly in the class is a declaration. The first three lines are declarations, so they're OK. The last four lines are not. That code should be inside a method somewhere. If you want to execute that code when the form loads then it should be in the Load event handler. This is pretty elementary stuff that any beginners tutorial would cover, so maybe you should work your way through such a tutorial.
First, create a method as shown below and check the exception.
Private Sub Utama_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Try
Dim connection As New MySqlConnection("Server=127.0.0.1;Database=pembelian;Uid=root;Pwd=;")
Dim da As New MySqlDataAdapter("select * from supplier", connection)
Dim dt As new DataTable
da.fill(dt)
ComboBox1.Datasource = dt
ComboBox1.DisplayMember = "npwp"
ComboBox1.ValueMember = "npwp"
Catch ex As Exception
MsgBox(ex.ToString)
End Try
End Sub

Save the image from the picturebox

Use this code to save the image from the PictureBox.
By saving the file and adding a name to it
The problem I'm facing, come on, when adjusting the image the following error occurs : - a generic error occurred in gdi+
My Code
show image
Using fs As New System.IO.FileStream("path", IO.FileMode.Open, IO.FileAccess.Read) PIC_PARTA.Image = System.Drawing.Image.FromStream(fs) End Using
save image
Dim pic As Image
pic = PIC_PARTA.Image
Dim Savefild As New SaveFileDialog
Savefild.FileName = TEXT_NAMEIMG.Text & ".PNG"
Savefild.ShowDialog()
pic.Save(Savefild.FileName, System.Drawing.Imaging.ImageFormat.Png)
LAB_path.Text = Savefild.FileName
Savefild.Dispose()
pic.Dispose()
This is not a full answer at this stage but it includes a significant amount of code, so I'll post as an answer and then either update or delete as required.
I just tried this code and all four saves worked, even though I thought that some may not:
Imports System.IO
Public Class Form1
Private ReadOnly folderPath As String = Path.Combine(My.Computer.FileSystem.SpecialDirectories.MyPictures, "Test")
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
PictureBox1.Image = Image.FromFile(Path.Combine(folderPath, "Picture1.png"))
Using fs = File.OpenRead(Path.Combine(folderPath, "Picture2.png"))
PictureBox2.Image = Image.FromStream(fs)
End Using
PictureBox3.ImageLocation = Path.Combine(folderPath, "Picture3.png")
PictureBox4.Load(Path.Combine(folderPath, "Picture4.png"))
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Try
PictureBox1.Image.Save(Path.Combine(folderPath, "Output1.png"))
Catch ex As Exception
MessageBox.Show(ex.ToString())
End Try
End Sub
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
Try
PictureBox2.Image.Save(Path.Combine(folderPath, "Output2.png"))
Catch ex As Exception
MessageBox.Show(ex.ToString())
End Try
End Sub
Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click
Try
PictureBox3.Image.Save(Path.Combine(folderPath, "Output3.png"))
Catch ex As Exception
MessageBox.Show(ex.ToString())
End Try
End Sub
Private Sub Button4_Click(sender As Object, e As EventArgs) Handles Button4.Click
Try
PictureBox4.Image.Save(Path.Combine(folderPath, "Output4.png"))
Catch ex As Exception
MessageBox.Show(ex.ToString())
End Try
End Sub
End Class
Can you please test that with your own images in your own folder and see if you get the same result?
Note that the Image.FromFile option locks the file until you dispose the Image. I have seen instances in the past where trying to save an Image created using Image.FromStream generates the error message you mentioned because it can't access the stream again later. Image.FromFile avoids that but has its own downsides.
My code that uses a FileStream directly is simpler and, therefore, better than yours but setting ImageLocation or calling Load is simpler again and thus better again. I suggest that you use one of those two options and see whether you still have an issue.

Refresh an UltraWinGrid from a separate form

I've got a form with a list of customers and another form where customers can be added. When I open the fAddCustomer form, from fCustomerList, I'm calling it using this code:
Dim f As New Form
f = New fAddCustomer(con, False)
f.MdiParent = Me.MdiParent
f.Show()
On fCustomerAdd, I've got a ToolStripButton to add the customer. When the form is closed, I need to refresh the UltraWinGrid that I have on fCustomerList to view the new data on the list automatically.
Because I'm using a ToolStripButton and the form uses f.MdiParent = Me.MdiParent, I can't use the same solution that was used in this answer here, as there is no DialogResult on a ToolStripButton, and you can't use ShowDialog when using MdiParents.
Is there any other way I can achieve this at all?
Here's a simple example:
' ... in fCustomerList ...
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim f As New fAddCustomer(con, False)
f.MdiParent = Me.MdiParent
AddHandler f.FormClosed, AddressOf f_FormClosed
f.Show()
End Sub
Private Sub f_FormClosed(sender As Object, e As FormClosedEventArgs)
' ... refresh your UltraWinGrid ...
End Sub
One that you could achieve this without changing the DataSource passing as #Plutonix suggested is to do something like this:
Private Sub fAddCustomer_FormClosing(sender As Object, e As FormClosingEventArgs) Handles Me.FormClosing
Try
If Application.OpenForms.OfType(Of fCustomerList).Any Then
Application.OpenForms("fCustomerList").Close()
Dim f As New fCustomerList()
f.MdiParent = Me.MdiParent
f.Show()
End If
Catch ex As Exception
Debug.WriteLine(ex.Message)
End Try
End Sub

Changes To Data Set Not Saving

When I add a new row to my data set it is visible on that specific form in the datagridview, however when I switch to another form with the same data bound datagridview the new row is not there. When I close the program my new row is completely gone then. I want to to save the new row to the Access database it is reading from.
Public Class frmAddStudent
Private Sub btnBack_Click(sender As Object, e As EventArgs) Handles btnBack.Click
Me.Hide()
frmUserControls.Show()
End Sub
Private Sub frmAddStudent_Load(sender As Object, e As EventArgs) Handles MyBase.Load
'TODO: This line of code loads data into the 'StudentRecords1DataSet.tblLecturer' table. You can move, or remove it, as needed.
Me.TblLecturerTableAdapter.Fill(Me.StudentRecords1DataSet.tblLecturer)
'TODO: This line of code loads data into the 'StudentRecords1DataSet.tblStudents' table. You can move, or remove it, as needed.
Me.TblStudentsTableAdapter.Fill(Me.StudentRecords1DataSet.tblStudents)
End Sub
Private Sub btnAdd_Click(sender As Object, e As EventArgs) Handles btnAdd.Click
Dim MyNewRow As DataRow
MyNewRow = StudentRecords1DataSet.tblStudents.NewRow
Try
With MyNewRow
.Item(1) = txtID.Text
.Item(2) = txtFirstName.Text
.Item(3) = txtSurname.Text
End With
Me.Validate()
Me.TblStudentsBindingSource.EndEdit() 'Change this to your binding source ' eg table'
Me.TableAdapterManager.UpdateAll(Me.StudentRecords1DataSet) ' chnage this to your database name'
MessageBox.Show("The Data Has Been Saved", "Information", MessageBoxButtons.OK)
Catch ex As Exception
'if there is a problem saving the data, it will show a messagebox with the problem as to why it could'nt save the data'
MessageBox.Show(ex.Message)
End Try
StudentRecords1DataSet.tblStudents.Rows.Add(MyNewRow)
StudentRecords1DataSet.tblStudents.AcceptChanges()
End Sub
Private Sub txtFirstName_MaskInputRejected(sender As Object, e As MaskInputRejectedEventArgs)
End Sub
Private Sub TblStudentsBindingNavigator_RefreshItems(sender As Object, e As EventArgs) Handles TblStudentsBindingNavigator.RefreshItems
End Sub
End Class
Any suggestions please?
UPDATe X2 based off your question update.
try this,
Public Class frmAddStudent
Private Sub btnBack_Click(sender As Object, e As EventArgs) Handles btnBack.Click
Me.Hide()
frmUserControls.Show()
End Sub
Private Sub frmAddStudent_Load(sender As Object, e As EventArgs) Handles MyBase.Load
'TODO: This line of code loads data into the 'StudentRecords1DataSet.tblLecturer' table. You can move, or remove it, as needed.
Me.TblLecturerTableAdapter.Fill(Me.StudentRecords1DataSet.tblLecturer)
'TODO: This line of code loads data into the 'StudentRecords1DataSet.tblStudents' table. You can move, or remove it, as needed.
Me.TblStudentsTableAdapter.Fill(Me.StudentRecords1DataSet.tblStudents)
End Sub
Private Async Sub btnAdd_Click(sender As Object, e As EventArgs) Handles btnAdd.Click
Try
Me.Validate()
Me.TblStudentsBindingSource.EndEdit() 'Change this to your binding source ' eg table'
Me.TableAdapterManager.UpdateAll(Me.StudentRecords1DataSet) ' chnage this to your database name'
MessageBox.Show("The Data Has Been Saved", "Information", MessageBoxButtons.OK)
Await Task.Delay(100)
TblStudentsBindingNavigator_RefreshItems.studentsBindingSource.AddNew()
Catch ex As Exception
'if there is a problem saving the data, it will show a messagebox with the problem as to why it could'nt save the data'
MessageBox.Show(ex.Message)
End Try
End Sub
Private Sub txtFirstName_MaskInputRejected(sender As Object, e As MaskInputRejectedEventArgs)
End Sub
Private Sub TblStudentsBindingNavigator_RefreshItems(sender As Object, e As EventArgs) Handles TblStudentsBindingNavigator.RefreshItems
End Sub
End Class

Using Background Worker VB.NET

I have to show many transaction on any table. It takes so much long time to process.
I want to use a background process in visual basic 2010, but it always give an error message like this "Cross thread operation detected". I have try so many ways that i found in the internet, but still can't find what the problem is.
Please help me about how to fix this problem.
This is my code :
Private Sub CHK_A_CheckedChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles CHK_A.CheckedChanged
Disabled()
P_Panel.Visible = True
B_Worker.RunWorkerAsync()
End Sub
Private Sub BTN_Search_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles BTN_Search.Click
USP_Select_Registration()
End Sub
Private Sub B_Worker_DoWork(ByVal sender As System.Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles B_Worker.DoWork
Threading.Thread.Sleep(25)
USP_Select_Registration()
End Sub
Private Sub B_Worker_RunWorkerCompleted(ByVal sender As Object, ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles B_Worker.RunWorkerCompleted
P_Panel.Visible = False
End Sub
This one is my store procedure
Public Sub USP_Select_Registration()
Dim Con As New SqlConnection(SQLCon)
Try
Con.Open()
Dim Cmd As New SqlCommand("USP_Select_Registration", Con)
Cmd.CommandType = CommandType.StoredProcedure
Cmd.Parameters.Add("#Check", SqlDbType.Bit).Value = CHK_A.EditValue
Cmd.Parameters.Add("#Month", SqlDbType.Int).Value = CBO_Month.SelectedIndex + 1
Cmd.Parameters.Add("#Year", SqlDbType.Int).Value = SPE_Year.EditValue
Cmd.Parameters.Add("#Search", SqlDbType.VarChar, 150).Value = TXT_Search.Text
DS_Registration.Tables("MST_Registration").Clear()
Dim Adt As New SqlDataAdapter(Cmd)
Adt.Fill(DS_Registration.Tables("MST_Registration"))
Catch ex As Exception
MsgBox(ex.Message, MsgBoxStyle.Critical, "Error")
Finally
Con.Close()
End Try
End Sub
I think you get error because inside of USP_Select_Registration you trying to read values from form control's. Which was created by another thread.
RunWorkComleted executes in the same thread where Backgroundworker was created, thats why code P_Panel.Visible = False will executes normally.
But DoWork executes on the another thread.
And when you tried to access some forms controls to read values
TXT_Search.Text - it raise error
You can pass you searching parameters to BackgroundWorker, but you need to add parameters to USP_Select_Registration function.
For example:
Private Sub USP_Select_Registration(searchText as String)
'Your code here
End Sub
Then where you start BackgroundWorker:
B_Worker.RunWorkerAsync(TXT_Search.Text)
And
Private Sub B_Worker_DoWork(ByVal sender As Object,
ByVal e As DoWorkEventArgs) Handles B_Worker.DoWork
Threading.Thread.Sleep(25)
USP_Select_Registration(e.Argument)
End Sub
In your case you need to pass more then one parameter.
So you can create some structure/class or whatever object where you can keep all needed values. And pass that object to RunWorkerAsync