Why isn't my thread doing anything? - vb.net

I have the following code in a form called Fetch.vb:
Imports System.ComponentModel ' might not be needed?
Imports System.Threading
Public Class Fetch
Public Sub New()
InitializeComponent()
backgroundWorker1.WorkerReportsProgress = True
backgroundWorker1.WorkerSupportsCancellation = True
End Sub
Private Sub btnFetch_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnFetch.Click
Dim ctrl As Control
For Each ctrl In Me.Controls
If TypeName(ctrl) = "TextBox" Then
If ctrl.Text.Length = (Not 0) Then
tbList.Add(ctrl.Text)
MsgBox(tbList.Item(0).ToString)
Exit For
End If
End If
Next
' ProcessLinks()
btnFetch.Enabled = False
BackgroundWorker1.RunWorkerAsync()
End Sub
Public Sub backgroundWorker1_DoWork(ByVal sender As System.Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
AddHandler BackgroundWorker1.DoWork, AddressOf backgroundWorker1_DoWork
ProcessLinks()
End Sub
End Class
Now process links is a module with a public sub in with the code I am trying to run, I don't need any arguments passed to it, and it doesn't do anything that (I think) could affect this, I think I'm just doing the threading code wrong. I have backgroundworker1 in my fetch.vb form, and when I click btn Fetch, the program does nothing.
Any help and guidance or reading material would be greatly appreciated.
EDIT Here is my LinkProcess module.
Public Module LinkProcess
Private Sub backgroundWorker1_DoWork(ByVal sender As System.Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles Fetch.BackgroundWorker1.DoWork
ProcessLinks()
End Sub
Public Sub ProcessLinks()
Dim tbContent As String
For Each tbContent In Fetch.tbList
Process.Start(tbContent)
Next
End Sub
End Module

What does your ProcessLinks() method do? Is it accessing any UI elements - like setting some text in label, or adding text a TextBox, etc.? If that is the case, then that won't work. You should not access the UI elements from inside your BackgroundWorker DoWork.
Here is a small post I wrote about how to use the BackgroundWorker correctly. This might help you.
http://www.vbforums.com/showthread.php?680130-Correct-way-to-use-the-BackgroundWorker

Related

Switching forms in vb.net

I am a volunteer for the National Park Service trying to convert an interactive display originally created 20 years ago in a language called ToolBook into Visual Basic. The program consists of several projects under a single solution. The starting project, called "MainMenu", can be thought of as a library, with buttons that bring up “books.” The project called Geology is an example “book” and GeologyMenu can be thought of as the index of a book. The buttons on GeologyMenu connect to “chapters” that explain and show examples of geologic processes in the park. The “chapters” are within the project “Geology” and work fine within the project. All forms used in the program have timers that allow the program to re-set itself to MainMenu when not in use.
In a previous post, with the help of Idle Mind (thank you again), the following code for works fine for going from MainMenu to GeologyMenu and in the reverse direction as long as no button is pushed on GeologyMenu. However, if I go to a “chapter” I can no longer get back to the MainMenu from the GeologyMenu. Here is the relevant code:
MainMenu
Public Class frmMainMenu
Private Sub BtnGeology_Click(sender As Object, e As EventArgs) Handles btnGeology.Click
Dim formNew As New Geology.frmGeologyMenu
AddHandler formNew.FormClosed, AddressOf formNew_FormClosed
TimerMain.Stop()
formNew.Show()
Me.Hide()
End Sub
Private Sub formNew_FormClosed(Sender As Object, e As FormClosedEventArgs)
lblTime.Text = 8
TimerMain.Start()
Me.Show()
End Sub
GeologyMenu
Public Class frmGeologyMenu
Public Sub frmGeologyMenu_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
lblTime.Text = 6
TimerGeologyMenu.Enabled = True
Me.Show()
End Sub
Private Sub BtnErosion_Click(sender As Object, e As EventArgs) Handles btnErosion.Click
TimerGeologyMenu.Stop()
frmErosionP01.Show()
Me.Hide()
End Sub
The code below for takes the viewer to the Erosion “chapter”
Private Sub BtnErosion_Click(sender As Object, e As EventArgs) Handles btnErosion.Click
TimerGeologyMenu.Stop()
frmErosionP01.Show()
Me.Hide()
End Sub
Erosion “Chapter” . This is the code for the button on every form in Erosion that takes the program back to GeologyMenu
Public Class frmErosionP02
Private Sub BtnGeologyMenu_Click(sender As Object, e As EventArgs) Handles btnGeologyMenu.Click
My.Computer.Audio.Stop()
frmGeologyMenu.lblTime.Text = 10
frmGeologyMenu.TimerGeologyMenu.Enabled = True
frmGeologyMenu.Show()
Me.Close()
End Sub
The code for forms within Erosion takes me back to GeologyMenu, but then MainMenu won’t show when I close GeologyMenu and I don’t understand why or how to fix it. Thank you in advance for your help!
Simply, pass the previous menu/Form to the new one in a parameterized constructor and keep it in a class variable, then handle the Form.Closed event of the new menu to show the previous one.
Example for the relevant code:
Public Class frmMainMenu
Inherits Form
Private Sub BtnGeology_Click(sender As Object, e As EventArgs) Handles btnGeology.Click
Dim formNew As New frmGeologyMenu(Me)
Me.Hide()
formNew.Show()
End Sub
End Class
Public Class frmGeologyMenu
Inherits Form
Private PreviousMenu As Form
Private Sub New()
InitializeComponent()
'...
End Sub
Sub New(prevMenu As Form)
Me.New()
PreviousMenu = prevMenu
AddHandler FormClosed,
Sub(s, e)
PreviousMenu.Show()
End Sub
End Sub
Private Sub BtnErosion_Click(sender As Object, e As EventArgs) Handles btnErosion.Click
Dim frmErosion As New frmErosionP02(Me)
Me.Hide()
frmErosion.Show()
End Sub
End Class
Public Class frmErosionP02
Inherits Form
Private PreviousMenu As Form
Private Sub New()
InitializeComponent()
'...
End Sub
Public Sub New(prevMenu As Form)
Me.New()
PreviousMenu = prevMenu
AddHandler FormClosed,
Sub(s, e)
PreviousMenu.Show()
End Sub
End Sub
End Class

Background Workers and Successive Events

I'm back again, with more code than last time. I may reference my previous questions here and there but this question is independent
I managed to convince my employer to drop the proprietary serial port communications library I was made to use, so now I am starting from scratch with SerialPorts and BackgroundWorkers so that I know how they work.
Here is my code:
Imports System
Imports System.IO.Ports
Public Class Form1
'SerialPort Port and BackgroundWorker Worker declared in form
Delegate Sub AppendText_Delegate(ByVal txtBox As TextBox, ByVal str As String)
Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
Port.PortName = ("COM9")
Port.BaudRate = 115200
Port.Parity = Parity.None
Port.StopBits = StopBits.One
Port.Handshake = Handshake.None
Port.ReadTimeout = 1000
Port.WriteTimeout = 1000
Port.Open()
AddHandler Port.DataReceived, AddressOf DataReceived
Worker.WorkerReportsProgress = True
Worker.WorkerSupportsCancellation = True
End Sub
Private Sub btnSend_Click(sender As System.Object, e As System.EventArgs) Handles btnSend.Click
Port.Write(txtInput.Text & vbCrLf)
End Sub
Private Sub DataReceived(sender As Object, e As SerialDataReceivedEventArgs)
Worker.RunWorkerAsync()
End Sub
Private Sub BackgroundWorker1_DoWork(sender As System.Object, e As System.ComponentModel.DoWorkEventArgs) Handles Worker.DoWork
If Worker.CancellationPending Then
e.Cancel = True
End If
AppendText_ThreadSafe(Me.txtOutput, Port.ReadLine())
End Sub
Private Sub AppendText_ThreadSafe(ByVal txtBox As TextBox, ByVal str As String)
If txtBox.InvokeRequired Then
Dim MyDelegate As New AppendText_Delegate(AddressOf AppendText_ThreadSafe)
Me.Invoke(MyDelegate, New Object() {txtBox, str})
Else
txtBox.AppendText(str)
End If
End Sub
End Class
At this moment I really not sure how the DataReceived event and the BackgroundWorker work together. Where should I put Worker.RunWorkerAsync() so that it calls DoWork() only when the DataReceived event is raised? Should I bind both events to the same method?
Thanks for your help, and apologies for the simplicity of this question. I've only just started with BackgroundWorkers and am still finding my footing, so to speak.
The DataReceived event of the SerialPort class is raised on a background thread, so it will not block the UI thread and you therefore don't need to use a BackgroundWorker in this case. Because DataReceived is called on a background thread, you will need to use Invoke if you need to update any UI controls from that handler.

Closing form after printing a web browser control contained in it

I'm taking some random print through the html and web browser control in vb.net winforms
Here is my code
Public Class Form1
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Dim myWebBrowser As New WebBrowser
AddHandler myWebBrowser.DocumentCompleted, AddressOf DocumentCompleted
myWebBrowser.Navigate("http://www.bing.com")
End Sub
Private Sub DocumentCompleted(ByVal sender As Object, ByVal e As WebBrowserDocumentCompletedEventArgs)
With DirectCast(sender, WebBrowser)
If .ReadyState = WebBrowserReadyState.Complete Then
.Print()
End If
End With
End Sub
End Class
I want the form to be closed after the print. Now if I write Me.Close() after .Print() nothing is being printed. what should I do to achieve this?
Any help is appreciated.
::Update::
after #Noseratio's suggestion I tried to handle the event onafterprint in my html and tried to invoke Me.Close() using ObjectFoprScripting set to my form. But that is firing the close method without any print.
Here is my code
script tag in my html page
<script>
function window.onafterprint() {
window.external.Test('called from script code');
}
</script>
VB.net Code of my form
Imports System.IO
Imports Microsoft.Win32
Imports System.Security.Permissions
<PermissionSet(SecurityAction.Demand, Name:="FullTrust")> _
<System.Runtime.InteropServices.ComVisibleAttribute(True)> _
Public Class Form1
Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
WebBrowser1.AllowWebBrowserDrop = False
WebBrowser1.IsWebBrowserContextMenuEnabled = False
WebBrowser1.WebBrowserShortcutsEnabled = False
webBrowser1.ObjectForScripting = Me
WebBrowser1.DocumentText = File.ReadAllText("localprint.htm")
End Sub
Public Sub Test(ByVal message As String)
MessageBox.Show(message, "client code")
Me.BeginInvoke(DirectCast(Sub() Me.Close(), MethodInvoker))
End Sub
Private Sub WebBrowser1_DocumentCompleted(sender As System.Object, e As System.Windows.Forms.WebBrowserDocumentCompletedEventArgs) Handles WebBrowser1.DocumentCompleted
WebBrowser1.Print()
End Sub
End Class
Found my solution
No need to handle onafterprint in javascript.
Here is what I did,
Step 1
Added a reference to SHDocVw.dll in my project. This can be found in c:\windows\system32 folder.
Step2
My new updated code
Imports System.IO
Imports Microsoft.Win32
Imports System.Security.Permissions
<PermissionSet(SecurityAction.Demand, Name:="FullTrust")> _
<System.Runtime.InteropServices.ComVisibleAttribute(True)> _
Public Class Form1
Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
WebBrowser1.AllowWebBrowserDrop = False
WebBrowser1.IsWebBrowserContextMenuEnabled = False
WebBrowser1.WebBrowserShortcutsEnabled = False
WebBrowser1.DocumentText = File.ReadAllText("localprint.htm")
End Sub
Private Sub WebBrowser1_DocumentCompleted_1(sender As System.Object, e As System.Windows.Forms.WebBrowserDocumentCompletedEventArgs) Handles WebBrowser1.DocumentCompleted
Dim wb As WebBrowser = TryCast(sender, WebBrowser)
Dim ie As SHDocVw.InternetExplorer = DirectCast(wb.ActiveXInstance, SHDocVw.InternetExplorer)
AddHandler ie.PrintTemplateInstantiation, AddressOf IE_OnPrintTemplateInstantiation
AddHandler ie.PrintTemplateTeardown, AddressOf IE_OnPrintTemplateTeardown
'Just to get reference of the webBrowser1 control in ie events, uncomment the below line
'ie.PutProperty("WebBrowserControl", DirectCast(wb, Object))
wb.Print()
End Sub
Private Sub IE_OnPrintTemplateInstantiation(pDisp As Object)
' The PrintTemplateInstantiation event is fired when the print job is starting.
End Sub
Private Sub IE_OnPrintTemplateTeardown(pDisp As Object)
' The PrintTemplateTeardown event is fired when the print job is done.
'Just to get reference of the webBrowser1 control, uncomment the below line
'Dim iwb2 As SHDocVw.IWebBrowser2 = TryCast(pDisp, SHDocVw.IWebBrowser2)
'Dim wb As WebBrowser = DirectCast(iwb2.GetProperty("WebBrowserControl"), WebBrowser)
Me.Close()
End Sub
End Class

Editing button properties from a module

I am just starting out with Visual basic .Net.
I can't seem to figure what's the scope of button properties like button.text. Can they be used outside the button_click event sub? And if so, how?
How can I modify button properties from a module in real time when a certain condition is met?
I'd surely appreciate some guidance and an example, if possible. Thanks.
Just as quick sample, I don't suggest doing something like this
I have 2 forms open, Form2 and Form3. Each form has a button on it.
I also have a Module, called MyModule
Public Class Form2
Public Sub ChangeButtonText(ByVal s As String)
Button1.Text = s
End Sub
End Class
.
Public Module MyModule
Sub ChangeForm2Btn()
Form2.ChangeButtonText("LOL")
End Sub
End Module
From my Form3 I click the button and call the module function to change Form2 button's text
Public Class Form3
Private Sub Form3_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
Form2.Show()
End Sub
Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
MyModule.ChangeForm2Btn()
End Sub
End Class
You could pass a reference to the button to a sub in the module, and then call that sub from the form.
i.e.
Public Class Form1
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
ChangeButtonText(Me.Button1, "Changed")
End Sub
End Class
Module modButton
Public Sub ChangeButtonText(ByRef Button As Button, ByVal Text As String)
Button.Text = Text
End Sub
End Module

Getting Build Errors in Program to Change Button Name When Clicked

Imports System
Imports System.Windows.Forms
Class MyButtonClass
Inherits Form
Private mrButton As Button
Public Sub MyButtonClass()
mrButton = New Button()
mrButton.Text = "Click me "
mrButton.Click += New System.EventHandler(MyButtonClickEventHandler)
Me.Controls.Add(mrButton)
End Sub
Shared Sub Main()
Application.Run(New MyButtonClass())
End Sub
Private Sub MyButtonClickEventHandler(ByVal sender As Object, ByVal e As EventArgs)
mrButton.Text = "You clicked me!"
End Sub
End Class
You're mixing C# and VB.Net code.
mrButton.Click += New system.EventHandler(MyButtonClickEventHandler)
Is C# syntax.
The button handler should either be declared as:
Private Sub MyButtonClickEventHandler(ByVal sender As Object, ByVal e As EventArgs) Handles mrButton.Click
Or you use the AddHandler as:
AddHandler mrButton.Click, AddressOf MyButtonClickEventHandler