In Vb.net, I want to show my main form and other form periodically.
The last form does check operations and automatically closes.
Should be implementing threads, but I am not sure if it's possible...
My code is empty..
Imports System
Imports System.Windows.Forms
Friend NotInheritable Class Program
Private Sub New()
End Sub
<STAThread() _
Shared Sub Main()
Application.EnableVisualStyles()
Application.SetCompatibleTextRenderingDefault(false)
Application.Run (New formMain()) '--> Main Form
'All code here is not execute until Main Form is closed
End Sub
End Class
Thanks in advance.
Edit: Sorry, I am a newbie in vb.net, I would want to say show my main form.
Edit 2: I think I didn't explain well, but with the help of #JeremyThompson I can complete my code.
FormMain: Now, When I try to close this form, I show another form to do check operations but I hold this (FormMain) always visible.
Private Sub FormMain_FormClosing(sender as Object, e as FormClosingEventArgs) _
Handles FormMain.FormClosing
Me.Visible = True
Dim anotherForm as New CheckOperationsForm()
anotherForm.Show()
e.Cancel = True
End Sub
Other form (or FormCheckOperations()): When the routine coded in this form is completed I establish the value of a boolean _successfulChecking, so if this boolean is true, main form keeps on showing, in another case, the application ends.
Private Sub FormCheckOperations_FormClosing(sender as Object, e as FormClosingEventArgs) _
Handles FormCheckOperations.FormClosing
If Not _succesfulChecking Then
End 'Close application
End If
End Sub
My doubt is, how I can show FormCheckOperation periodically from MainForm (I could call FormMain.Close() to do it) or how do it from Main Sub?
Edit 3: Now, In my current approach, I open 2 threads in Main Sub, the first one with the Main Form and the second one with another thread which opens CheckOperations Forms each 60 seconds. But when executes in Visual Studio, forms stay "behind" of the SDK, furthermore, they are not working properly, but I think the final way should be closer.
Imports System
Imports System.Windows.Forms
Friend NotInheritable Class Program
Private Sub New()
End Sub
<STAThread() _
Shared Sub Main()
Application.EnableVisualStyles()
Application.SetCompatibleTextRenderingDefault(false)
Dim threadFormMain As New Thread (AddressOf launchFrmMain)
Dim threadFormCheckOperations As New Thread (AddressOf launchThreadFrmCheckOperations)
threadFormMain.Start()
threadFormCheckOperations.Start()
End Sub
Public Shared Sub launchFrmMain()
Application.Run(New FormMain()
End Sub
Public Shared Sub launchThreadFrmCheckOperations()
While(True)
Dim threadForm As New Thread(AddressOf launchFrmCheckOperations)
threadForm.Start()
'Here I should stop while loop during 60 secs…
'Thread.Sleep(60000)
End While
End Sub
Public Shared Sub launchFrmCheckOperations()
Application.Run(New FormCheckOperations()
End Sub
End Class
In the FormMain_Closing event, set Visible = False, instantiate and show another form and set e.cancel = True, then put code in the anotherform's closing event to End the application.
eg:
Private Sub FormMain_FormClosing(sender as Object, e as FormClosingEventArgs) _
Handles FormMain.FormClosing
Me.Visible = False
Dim anotherForm as New AnotherForm()
anotherForm.Show()
e.Cancel = True
End Sub
Finally I solved this.
In Main Sub firstly launches a thread with check operation forms (globally declared) and later launches mainForm in main thread.
The thread with check operations contains while loop which creates a new thread in each iteration, but with Thread.Join() stays waiting the end of previous thread, so it avoids to create other thread while there is a thread opened.
The code is the following:
Imports System
Imports System.Windows.Forms
Friend NotInheritable Class Program
Private Sub New()
End Sub
<STAThread() _
Shared Sub Main()
Application.EnableVisualStyles()
Application.SetCompatibleTextRenderingDefault(false)
threadFormCheckOperations.Start()
Application.Run(New FormMain())
End Sub
Public Shared threadFormCheckOperations As New Thread(AddressOf launchThreadFrmCheckOperations)
Public Shared Sub launchThreadFrmCheckOperations()
While(True)
Dim threadForm As New Thread(AddressOf launchFrmCheckOperations)
threadForm.Start()
threadForm.Join() '---> Wait until thread is closed
Thread.Sleep(60000)
End While
End Sub
Public Shared Sub launchFrmCheckOperations()
Application.Run(New FormCheckOperations()
End Sub
End Class
Related
I have pretty much the same problem as described in this, but using VB.NET. There is a Form1 which is opened automatically as start window, so I cannot find the instance to use for accessing it. There is a Form2 opened from within Form1. I try to pass the instance of Form1 using keyword "Me":
Private Sub Button1_click(...) Handles Button1.Click
Dim childform as new Form2(Me)
childform.show()
End Sub
In Form2 I have:
Public Sub New(parentform As System.Windows.Forms.Form)
InitializeComponents()
MessageBox.Show(parentform.Button1.Text)
End Sub
Upon compiling I get the error: "Button1 is not a member of Form".
So how to pass the Form1 instance correctly to Form2?
Also I want to change some properties of the Button1 of Form1 from Form2. Button1 is declared in a Private Sub, will I nevertheless be able to access it from Form2 if I pass the instance correctly? If not, can I declaring a sub in Form1, e.g.
Public Shared Sub ChangeText(newtext As Sting)
Me.Button1.Text=newtext
End Sub
that will do the job?
I'm not 100% sure about what you are trying to achieve, but, you can pass data between forms. So for example you can do something like:
Public Class Form1
Private Sub Button1_click(...) Handles Button1.Click
Dim newForm2 as New Form2()
newForm2.stringText = ""
If newForm2.ShowDialog() = DialogResult.OK Then
Button1.Text = newForm2.stringText
End If
End Sub
End Class
And in Form2 you have
Public Class Form2
Dim stringText as string
Private Sub changeStringText()
'your method to change your data
Me.DialogResult = DialogResult.OK 'this will close form2
End Sub
End Class
I hope this is what you need, if not let me know
Thanks for your answer and comment. So I declared the wrong class for the parentform, means in Form2 it needs to be "parentform as Form1":
Public Sub New(parentform As Form1)
InitializeComponents()
MessageBox.Show(parentform.Button1.Text)
End Sub
and yes, I need to skip the "shared" in the ChangeText:
Public Sub ChangeText(newtext As Sting)
Me.Button1.Text=newtext
End Sub
This way it worked for me.
On every DataGridView1_SelectionChanged event I need to run a Private Sub OnSelectionChanged() of the form that is loaded into Panel1 (see the image http://tinypic.com/r/2nu2wx/8).
Every form that can be loaded into Panel1 has the same Private Sub OnSelectionChanged() that initiates all the necessary calculations. For instance, I can load a form that calculates temperatures or I can load a form that calculates voltages. If different element is selected in the main form’s DataGridView1, either temperatures or voltages should be recalculated.
The problem is - there are many forms that can be loaded into Panel1, and I’m struggling to raise an event that would fire only once and would run the necessary Sub only in the loaded form.
Currently I’m using Shared Event:
'Main form (Form1).
Shared Event event_UpdateLoadedForm(ByVal frm_name As String)
'This is how I load forms into a panel (in this case frm_SCT).
Private Sub mnu_SCT_Click(sender As Object, e As EventArgs) Handles mnu_SCT.Click
frm_SCT.TopLevel = False
frm_SCT.Dock = DockStyle.Fill
Panel1.Controls.Add(frm_SCT)
frm_SCT.Show()
Var._loadedForm = frm_SCT.Name
RaiseEvent event_UpdateLoadedForm(Var._loadedForm)
End Sub
‘Form that is loaded into panel (Form2 or Form3 or Form4...).
Private WithEvents myEvent As New Form1
Private Sub OnEvent(ByVal frm_name As String) Handles myEvent.event_UpdateLoadedForm
‘Avoid executing code for the form that is not loaded.
If frm_name <> Me.Name Then Exit Sub
End Sub
This approach is working but I’m sure it can be done way better (I'd be thankful for any suggestions). I have tried to raise an event in the main form like this:
Public Event MyEvent As EventHandler
Protected Overridable Sub OnChange(e As EventArgs)
RaiseEvent MyEvent(Me, e)
End Sub
Private Sub DataGridView1_SelectionChanged(sender As Object, e As EventArgs) _
Handles DataGridView1.SelectionChanged
OnChange(EventArgs.Empty)
End Sub
but I don't know to subscribe to it in the loaded form.
Thank you.
Taking into account Hans Passant’s comments as well as code he posted in related thread I achieved what I wanted (see the code below).
Public Interface IOnEvent
Sub OnSelectionChange()
End Interface
Public Class Form1
' ???
Private myInterface As IOnEvent = Nothing
' Create and load form.
Private Sub DisplayForm(frm_Name As String)
' Exit if the form is already displayed.
If Panel1.Controls.Count > 0 AndAlso _
Panel1.Controls(0).GetType().Name = frm_Name Then Exit Sub
' Dispose previous form.
Do While Panel1.Controls.Count > 0
Panel1.Controls(0).Dispose()
Loop
' Create form by its full name.
Dim T As Type = Type.GetType("Namespace." & frm_Name)
Dim frm As Form = CType(Activator.CreateInstance(T), Form)
' Load form into the panel.
frm.TopLevel = False
frm.Visible = True
frm.Dock = DockStyle.Fill
Panel1.Controls.Add(frm)
' ???
myInterface = DirectCast(frm, IOnEvent)
End Sub
Private Sub DataGridView1_SelectionChanged(sender As Object, e As EventArgs) _
Handles DataGridView1.SelectionChanged
' Avoid error if the panel is empty.
If myInterface Is Nothing Then Return
' Run subroutine in the loaded form.
myInterface.OnSelectionChange()
End Sub
End Class
One last thing – it would be great if someone could take a quick look at the code (it works) and confirm that it is ok, especially the lines marked with “???” (I don’t understand them yet).
This is my situation, there are 2 Classes and my main form Form1:
Class1: has a method doSomethingAndCall(callback) which creates a new thread
Class2: has dynamic created controls with a button that fires Class1.doSomethingAndCall(newCallback)
in code it looks like this (it starts at Class2.Button_Click):
Class Class1
public shared sub doSomethingAndCallAsync(state as object)
Console.WriteLine(Form1.InvokeRequired) 'output: false
Console.WriteLine(Form1.IsHandleCreated) 'output: false
Form1.Invoke(state.callback) 'throws System.InvalidOperationException
end sub
public shared sub doSomethingAndCall(callback as object)
System.Threading.ThreadPool.QueueUserWorkItem(AddressOf doSomethingAndCallAsync, New With {.callback = callback})
end sub
End Class
Class Class2
Public Delegate Sub doSomethingDelegate()
Public Sub doSomething()
Console.WriteLine("success!")
End Sub
Public Sub Button_Click(ByVal sender As Object, ByVal e As System.EventArgs)
Class1.doSomethingAndCall(New doSomethingDelegate(AddressOf doSomething))
End Sub
End Class
The exact exception I get is:
Invoke or BeginInvoke cannot be called on a control until the window handle has been created
and as I can see the console.WriteLine in line 4 shows me that the form is realy not created. So I added this handlers, and now it get's really confusing:
Private Sub Form1_HandleCreated(sender As Object, e As System.EventArgs) Handles Me.HandleCreated
Console.WriteLine("Handle created") 'Output: Handle created, when running program
End Sub
Private Sub Form1_HandleDestroyed(sender As Object, e As System.EventArgs) Handles Me.HandleDestroyed
Console.WriteLine("Handle destroyed") 'Will never Output!
End Sub
So it's created and never destroyed but if i click the button it's nevertheless not avaible? -Can anyone explain me what is going on and how to call a callback correct, thanks!
The instance of My.Forms.Form1 aka. Form1 will be different in each thread. You need a handle to the correct instance. Drop a button onto your Form1 and add the following code:
Public Class Form1
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Threading.Tasks.Task.Factory.StartNew(Sub() Class1.Wrong())
Threading.Tasks.Task.Factory.StartNew(Sub() Class1.Correct(Me))
End Sub
End Class
Public Class Class1
Public Shared Sub Wrong()
Debug.WriteLine(String.Format("(Other thread, wrong) InvokeRequired={0}, IsHandleCreated={1}", Form1.InvokeRequired, Form1.IsHandleCreated))
End Sub
Public Shared Sub Correct(instance As Form1)
Debug.WriteLine(String.Format("(Other thread, correct) InvokeRequired={0}, IsHandleCreated={1}", instance.InvokeRequired, instance.IsHandleCreated))
End Sub
End Class
Output
(Other thread, correct) InvokeRequired=True, IsHandleCreated=True
(Other thread, wrong) InvokeRequired=False, IsHandleCreated=False
I’m working on a scheduler like project using VB.Net, the application start from “Sub Main” with Application.Run(), all program codes are handler in a class, which is created and started here,
Public Sub Main()
m_App = New myApp
m_App.Start()
Application.Run()
End Sub
Inside the myApp, there has a timer to control the execution of task, and it will start a thread for each task, when the task complete, we try to display the alert window if there has error detected. We have tested two different way for communization between the execute thread and the main thread in order to display the alert window (frmAlert):
1) by adding pulic event in task object, then addhandler to the function in main thread
2) use delegate to notify the main thread
However, the alert window cannot be shown and there has no error reported. After debuging with the IDE, it was found that the alert windows has successful displayed, but it will closed when the task thread is completed.
Here is a simplified task class (testing with two communization methods),
Public Class myProcess
Public Event NotifyEvent()
Public Delegate Sub NotifyDelegate()
Private m_NotifyDelegate As NotifyDelegate
Public Sub SetNotify(ByVal NotifyDelegate As NotifyDelegate)
m_NotifyDelegate = NotifyDelegate
End Sub
Public Sub Execute()
System.Threading.Thread.Sleep(2000)
RaiseEvent NotifyEvent()
If m_NotifyDelegate IsNot Nothing Then m_NotifyDelegate()
End Sub
End Class
And the main application class
Imports System.Threading
Public Class myApp
Private WithEvents _Timer As New Windows.Forms.Timer
Private m_Process As New myProcess
Public Sub Start()
AddHandler m_Process.NotifyEvent, AddressOf Me.NotifyEvent
m_Process.SetNotify(AddressOf NotifyDelegate)
ProcessTasks()
End Sub
Private Sub Timer_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles _Timer.Tick
ProcessTasks()
End Sub
Public Sub ProcessTasks()
_Timer.Enabled = False
'
Dim m_Thread = New Thread(AddressOf m_Process.Execute)
m_Thread.Start()
'
_Timer.Interval = 30000
_Timer.Enabled = True
End Sub
Public Sub NotifyEvent()
frmAlert.Show()
End Sub
Public Sub NotifyDelegate()
frmAlert.Show()
End Sub
End Class
It was found that the frmAlert is shown by using either NotifyEvent or NotifyDelegate, but it is closed immediately when the Execute is finished.
May I know how we can popup an alert window from the execution thread which can stay in the screen until user close it?
Thanks in advance!
You need to ensure that your main thread does not terminate if you want it to do anything when a sub-thread raises and event.
Public Sub Start()
AddHandler m_Process.NotifyEvent, AddressOf Me.NotifyEvent
m_Process.SetNotify(AddressOf NotifyDelegate)
ProcessTasks()
Do While True 'You might want to add a boolean condition here to instruct the main program to terminate when you want it to.
System.Threading.Thread.Sleep(200)
Loop
End Sub
This will prevent the main thread (program) to end, and thus will be available to handle any events raised by the sub-threads. Note: Your class lacks a termination condition.
Imports System
Imports System.Net
Imports System.IO
Imports System.Threading.Thread
Public Class Form1
Public errorz As String
Public votestatus As String
Public videoid As String
Public votetries As String
Public Sub Main()
End Sub
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
If RadioButton1.Checked Then
votestatus = "YES"
End If
If RadioButton2.Checked Then
votestatus = "NO"
End If
videoid = TextBox1.Text
votetries = TextBox2.Text
For i As Integer = 1 To votetries Step 1
MsgBox("Hi")
Sleep(5000)
Next
End Sub
End Class
What happens right now is that it runs, and freezes during the loop.
I would like another button when clicked will stop the loop.
Also the Sleep function doesn't seem to be working because I get "Hi" alert every millisecond.
you have to run the long operation in a background thread in order not to block the UI thread, such as BackgroundWorker class in c#, don't know if it is available in vb.
You can use a BackgroundWorker in VB.
Alternatively, if you need to make sure buttons are processed while a loop is executing, you can add application.doevents inside the loop. You can use event handlers for the buttons you want to use to interrupt the loop, and set a flag variable that the loop can check for.