How to close a form that open by a BackgroundWorker.? I need to close Form3 end of the Button1_Click. This is my code.
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
BackgroundWorker1.RunWorkerAsync()
con.Open()
Dim cmd As New SqlCommand(("SELECT * FROM sales"), con)
Dim da As New SqlDataAdapter
Dim ds As New Data.DataSet
da.SelectCommand = cmd
cmd.ExecuteNonQuery()
ds.Clear()
da.Fill(ds, "sales")
con.Close()
DataGridView1.DataSource = ds
DataGridView1.DataMember = "sales"
Form3.Close()
End Sub
Private Sub BackgroundWorker1_DoWork(sender As Object, e As DoWorkEventArgs) Handles BackgroundWorker1.DoWork
Form3.ShowDialog()
End Sub
The problem with your code is that, by using the class name, you are using the default instance and default instances are thread-specific. That means that the Form3 instance that you're referring to in the DoWork event handler, which is executed on a secondary thread, is a different instance than the one you're referring to in the Click event handler, which is executed on the UI thread. In order to refer to the same instance, you would need to create an instance yourself and use that in both cases.
Private f3 As Form3
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
BackgroundWorker1.RunWorkerAsync()
'...
f3.Close()
End Sub
Private Sub BackgroundWorker1_DoWork(sender As Object, e As DoWorkEventArgs) Handles BackgroundWorker1.DoWork
f3 = New Form3
f3.ShowDialog()
End Sub
That code is problematic though, because you're then calling the Close method on a thread other than the one the form was created on. To avoid that, you need to marshal a method call to the thread that the form was created on.
f3.Invoke(Sub() f3.Close())
That addresses your question but the real issue here is that you are trying to display a modal dialogue to prevent access to the calling form while it's doing some work but you're failing in that aim. Because you're calling ShowDialog on a secondary thread, it won't actually behave the way a modal dialogue should. That's because modality is thread-specific too.
You're actually doing things the wrong way around. You should not be displaying the form on a secondary thread and doing the work on the UI thread. Rather, you should be displaying the form on the UI thread and doing the work on a secondary thread.
Click here for a demo that does as I describe in that last paragraph.
Related
I've recently moved over to Visual Studio 2019 V16.2 and it's now showing me a new "message" whenever I move between forms in my Windows Forms App.
IDE0067 Disposable object created by 'New FindFile' is never disposed
I've always moved to the "next" form in my project with code snippets like:
Private Sub Button4_Click(sender As Object, e As EventArgs) Handles Button4.Click
Dim frmFindFile As New FindFile
frmFindFile.Show()
Me.Close()
End Sub
What am I doing wrong? Should I be disposing of the form variable once the new one is showing? The below gets rid of the warning, but my second form never shows up!
Private Sub Button4_Click(sender As Object, e As EventArgs) Handles Button4.Click
Dim frmFindFile As New FindFile
frmFindFile.Show()
Me.Close()
frmFindFile.Dispose()
End Sub
VB.NET has default instances of forms, so if you just use FindFile.Show() it will not give a warning.
For more information, please see the answers at Why is there a default instance of every form in VB.Net but not in C#?
I haven't seen the proper answer to this question yet, but there is one.
Original code as listed above is:
Private Sub Button4_Click(sender As Object, e As EventArgs) Handles Button4.Click
Dim frmFindFile As New FindFile
frmFindFile.Show()
Me.Close()
End Sub
Yet, the proper way to do this is:
Private Sub Button4_Click(sender As Object, e As EventArgs) Handles Button4.Click
Using frmFindFile As FindFile = New FindFile()
frmFindFile.Show()
End Using
Me.Close()
End Sub
This will automatically dispose of anything within the Using structure that requires disposal.
Pretty much anything that can be instantiated using the Dim/As class structure can be placed within a Using structure.
Another example would be using streamreader/writer. Instantiate it with the Using, then instead of using instance.Close(), just use End Using to close it out and dispose of it.
First off, pardon me if my English is bad, I'm not a native English speaker.
I'm fairly new to programming and I'm trying to teach myself VB.NET
I came across a problem while trying to learn about Delegates. (see code below)
What I'm trying to accomplish is to update a specified Control's text property via a thread. However, as soon as I start the thread, I get an ArgumentException Error. I have completely no idea what's wrong. Anybody have an idea what i've done wrong here?
Public Class Form1
Delegate Sub myDelegate1(ByVal s_Name As Control, ByVal s_txt As String)
Public txtUpdate As New myDelegate1(AddressOf upd_ControlTextProperty)
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Label1.Text = vbnullstring
End Sub
Private Sub upd_ControlTextProperty(ByVal ControlName As Control, ByVal txt As String)
ControlName.Text = txt
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim thread1 As New Threading.Thread(AddressOf threadstart)
thread1.IsBackground = True
thread1.Start()
End Sub
Private Sub threadstart()
Me.Invoke(Me.txtUpdate, New Object(), {Label1, "This is Label 1"})
End Sub
End Class
As TheValyreanGroup said, your delegate is supposed to accept two arguments, and you pass it three :
Me.Invoke(Me.txtUpdate, New Object(), {Label1, "This is Label 1"})
^-1--------^ ^-2--------^ ^-3-----------------------^
So just remove the New Object() thing, and transform this {Label1, ...} into just a string :
Me.Invoke(Me.txtUpdate, "This is Label 1")
OK Better that way.
On a second hand, what you are doing is not very usefull.
You create a new Thread from your UI Thread.
With this new Thread, you invoke back the UI Thread and you stop your Thread...
Remember that a Control can be updated only by the Thread who created the Form (the UI thread).
Unless you have a good reason to work with your background thread, you can resume your code to :
Public Class Form1
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Label1.Text = vbnullstring
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Label1.Text = "This is Label 1"
End Sub
End Class
UPDATE
(from comments)
To make it more clear, here is a schema (that I took on https://androidkennel.org/android-networking-tutorial-with-asynctask/, if any restrictions apply I will remove the image)
The Main UI Thread is used for things :
React to user events (clicks, inputs...) and start background threads that will do the process
Update the User Interface when the background thread is over or during the task.
When I say what you're doing is not usefull is because your background thread does not do any processing, it just signals the UI thread to update the UI...
I would try this approach. upd_ControlTextProperty can be called successfully either from the UI thread or your new thread.
Public Class Form1
Delegate Sub myDelegate1(ByVal s_Name As Control, ByVal s_txt As String)
Public txtUpdate As New myDelegate1(AddressOf upd_ControlTextProperty)
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Label1.Text = ""
End Sub
Private Sub upd_ControlTextProperty(ByVal ControlName As Control, ByVal txt As String)
If Me.InvokeRequired = True Then
Me.Invoke(txtUpdate, New Object() {ControlName, txt})
Else
ControlName.Text = txt
End If
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim thread1 As New Threading.Thread(AddressOf threadstart)
thread1.IsBackground = True
thread1.Start()
End Sub
Private Sub threadstart()
upd_ControlTextProperty(Label1, "This is Label 1")
End Sub
End Class
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
Having a problem linking my form3 back to form2 in windows forms. I want the "back" button to take me back to form 2 but it doesnt do so. I am trying form2.show() but it doesnt work.
My current form3 code:
Public Class Form3
Private Sub CheckedListBox1_SelectedIndexChanged(sender As Object, e As EventArgs) Handles CheckedListBox1.SelectedIndexChanged
MessageBox.Show("Developer Succsessfully Added to Sprint", "Developer Added")
End Sub
Private Sub Form3_Load(sender As Object, e As EventArgs) Handles MyBase.Load
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
**Form2.Show()**
End Sub
End Class
What happening is most likely you already closed your form and can't open it again.
Assuming, you have both instances well and alive
In Form2 you should have
me.Hide()
Form3.Show()
And In Form3 you should have
me.Hide()
Form2.Show()
It can be something like this
shared sub Main
dim f2 as new Form2()
dim f3 as new Form3()
f2.Next = f3
f3.previous = f2
end sub
To link forms you creating properties, Next and Previous
And then use that as way to operate the form that should open
In form code do
private sub BtnNext_Click(....).....
Me.Hide()
Me.Next.Show()
End Sub
and the same way for the previous. If you have wizard, you could chain all your forms this way.
and of course, to accomplish this, minimum, you need an interface that contracts your forms to implement Properties Next and Previous or you can have a base class with implementation of the buttons and properties and then it will all work.
simple code redirect one form1 to form2 Using C#
Form2 f2=new Form2();
f2.show() OR f2.ShowDialog();
I have a VB program that has two forms, i have coded the form load of each forms.
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
MessageBox.Show("I AM FORM 1")
End Sub
Private Sub Form2_Load(sender As Object, e As EventArgs) Handles MyBase.Load
MessageBox.Show("I AM FORM 2")
End Sub
Here is how i switch through Form1 and Form2, i made use of a button.
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Me.Hide()
Form1.Show()
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Me.Hide()
Form2.Show()
End Sub
But everytime i switch forms the form load event will only trigger once. Is there something wrong with my code? I am guesing the Me.Hide() will only hide the previous form and not totally close it. I want to be able to close the previous form so that when i will open it again, the form load event will trigger again.
But everytime i switch forms the form load event will only trigger once. Is there something wrong with my code? I am guesing the Me.Hide() will only hide the previous form and not totally close it.
This is exactly what is happening. The Hide method just hides the form from the user, effectively making it invisible.
What you're looking for is the Close method, which actually closes the form. (Since you are displaying the form using the Show method, you do not need to call Dispose.)
You will, however, not be able to close a form and continue to run code in its methods. So you'll need to reverse the order of the statements in your event handler functions, displaying the other form first and then closing itself. Make them look like this:
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Form1.Show()
Me.Close()
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Form2.Show()
Me.Close()
End Sub
That will do what you want. The Load event will be triggered each time you call the Show method, because you're creating and showing a new form.
It is worth pointing out, though, that you're relying on an unusual characteristic of VB.NET, one that it retains from the older VB languages for backwards compatibility reasons. Instead of referring to an object of your form class (like you would have to do with all other class objects), you are referring to it by the type name (the name of the class itself). You really shouldn't do that, it causes all sorts of headaches and will confuse people reading your code. It is better to just instantiate a new form object, like this:
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim frm As New Form1 ' create a new Form1 object
frm.Show() ' ... and display it
Me.Close()
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim frm As New Form1 ' create a new Form2 object
frm.Show() ' ... and display it
Me.Close()
End Sub
When you run this code, you will likely run immediately into another problem: the first time you close Form1, your entire application will quit. This is because, by default for a new project, Form1 is designated as the "Startup form" in your project's properties ("My Project" in the Solution Explorer). You will either have to:
create a third form to use as the "main" form, and set the "Startup form" to this third form, or
change the "Shutdown mode" (also in "My Project") from "When startup form closes" to "When last form closes".
I am guesing the Me.Hide() will only hide the previous form and not totally close it
Yes, it does what it says. If you want to close the form then use Me.Close() instead. The Load event will fire again when you create the new instance.
You'll have to change a setting to ensure that doesn't also close your application. Project + Properties, Application tab, change the Shutdown mode setting to "When last form closes". And put the Me.Close() call after the Show() call.
I also had a similar question. When u .Hide() you are just storing it away in memory somewhere such that when it is re-opened it doesnt have to make a new form just recalls the one from memory hence that method is not called again. You have to destroy the form. So what you can do when navigating to another form is go to that form first and then destroy the current form like so Form2.Show()Me.Close(). Look at my question and my accepted answer. If that works please dont forget to tick this as your accepted answer.
When my form is hidden and reloaded from another form it is not executing the code in the Load event
If MessageBox.Show("Are you sure to close this application?", "Close",
MessageBoxButtons.YesNo, MessageBoxIcon.Question) = Windows.Forms.DialogResult.Yes Then
frmIndex.Show() //the main form
Else
e.Cancel = True
Me.Show() // The form open
End If
The form open going closing and going back to the main/index form. hope it help :) just play with the .show, .hide and e.cancel
I think you using a silly construction, but you should;
Private Sub Form2_Shown(sender As Object, e As EventArgs) Handles Me.Shown
Form1.close()
End Sub
Use the Shown event.
And use ShowDialog()
Form1.ShowDialog()
Yes. What you are doing is closing the form before it could open up form2.
Instead Of:
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Me.Hide()
Form1.Show()
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Me.Hide()
Form2.Show()
End Sub
You Need To Put:
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Form1.show
Me.hide
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Form2.show
Me.hide
End Sub
If This Helps, Please Reply.