I am trying to limit the time to open webbrowser in vb.net; The conclusion after lots of search seems the threading! I tried the code below; that includes 2 methods I've tried, but nothing working;
I am trying to open the website in 10 seconds in another thread, if website did not respond, then go to the next website and discard that one; my codes are below:
FIRST TRIAL:
Option Explicit On
Option Strict On
Imports System.Threading
Public Class Form1
Dim WorkerThread As Thread
Dim StopThread As Boolean = True
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
MessageBox.Show(" ************************** This is the MAIN thread ************************** ")
End Sub
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
MessageBox.Show(" ************************** This is the SECOND thread ************************** ")
If StopThread = False Then
StopThread = True
Else
StopThread = False
WorkerThread = New Thread(AddressOf Navigate)
WorkerThread.IsBackground = True
WorkerThread.Start()
End If
End Sub
Sub Navigate()
WebBrowser1.Navigate("http://www.mekdam.com")
While WebBrowser1.ReadyState <> WebBrowserReadyState.Complete
Application.DoEvents()
End While
End Sub
End Class
SECOND TRIAL
Option Explicit On
Option Strict On
Imports System.Threading
Public Class Form1
Dim WorkerThread As Thread
Dim StopThread As Boolean = True
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
MessageBox.Show(" ************************** This is the MAIN thread ************************** ")
End Sub
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
MessageBox.Show(" ************************** This is the SECOND thread ************************** ")
If StopThread = False Then
StopThread = True
Else
StopThread = False
WorkerThread = New Thread(AddressOf Navigate)
WorkerThread.IsBackground = True
WorkerThread.Start()
End If
End Sub
Sub Navigate()
WebBrowser1.Navigate("http://www.mekdam.com")
While WebBrowser1.ReadyState <> WebBrowserReadyState.Complete
Application.DoEvents()
End While
End Sub
End Class
Related
I am trying to implement BackgroundWorker in my vb.net code. I understand you cannot update the UI from the background worker. Since when setting breakpoints in my code in the Backgroundworker.DoWork sub I would get
Me.Accessibility.Object threw an exception of type 'System.InvalidOperationException'
Message "Cross-thread operation not valid: Control 'FrmLoad' accessed from a thread other than the thread it was created on."
To try to understand why this was happening I copied the code EXACTLY from
https://learn.microsoft.com/en-us/dotnet/api/system.componentmodel.backgroundworker?view=netframework-4.7.2
and when setting a breakpoints again in the DoWork sub I get the same exception. I have tried several other microsoft code examples with the same issue. Is there something wrong with the code?
Imports System
Imports System.ComponentModel
Imports System.Windows.Forms
Namespace BackgroundWorkerSimple
Public Partial Class Form1
Inherits Form
Public Sub New()
InitializeComponent()
backgroundWorker1.WorkerReportsProgress = True
backgroundWorker1.WorkerSupportsCancellation = True
End Sub
Private Sub startAsyncButton_Click(ByVal sender As Object, ByVal e As EventArgs)
If backgroundWorker1.IsBusy <> True Then
backgroundWorker1.RunWorkerAsync()
End If
End Sub
Private Sub cancelAsyncButton_Click(ByVal sender As Object, ByVal e As EventArgs)
If backgroundWorker1.WorkerSupportsCancellation = True Then
backgroundWorker1.CancelAsync()
End If
End Sub
Private Sub backgroundWorker1_DoWork(ByVal sender As Object, ByVal e As DoWorkEventArgs)
Dim worker As BackgroundWorker = TryCast(sender, BackgroundWorker)
For i As Integer = 1 To 10
If worker.CancellationPending = True Then
e.Cancel = True
Exit For
Else
System.Threading.Thread.Sleep(500)
worker.ReportProgress(i * 10)
End If
Next
End Sub
Private Sub backgroundWorker1_ProgressChanged(ByVal sender As Object, ByVal e As ProgressChangedEventArgs)
resultLabel.Text = (e.ProgressPercentage.ToString() & "%")
End Sub
Private Sub backgroundWorker1_RunWorkerCompleted(ByVal sender As Object, ByVal e As RunWorkerCompletedEventArgs)
If e.Cancelled = True Then
resultLabel.Text = "Canceled!"
ElseIf e.[Error] IsNot Nothing Then
resultLabel.Text = "Error: " & e.[Error].Message
Else
resultLabel.Text = "Done!"
End If
End Sub
End Class
End Namespace
It's not actually hindering the code from running, but I want to make sure that the thread is actually remaining safe.
That sample code is written in C#, and you apparently left out a function and it’s call:
// Set up the BackgroundWorker object by
// attaching event handlers.
private void InitializeBackgroundWorker()
{
backgroundWorker1.DoWork +=
new DoWorkEventHandler(backgroundWorker1_DoWork);
backgroundWorker1.RunWorkerCompleted +=
new RunWorkerCompletedEventHandler(
backgroundWorker1_RunWorkerCompleted);
backgroundWorker1.ProgressChanged +=
new ProgressChangedEventHandler(
backgroundWorker1_ProgressChanged);
}
While this can be rewritten using addhandler, the vbish way to do this is to add a handles clause to you method declaration.
I believe this is what you are looking for:
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
InitializeComponent()
BackgroundWorker1.WorkerReportsProgress = True
BackgroundWorker1.WorkerSupportsCancellation = True
End Sub
Private Sub startAsyncButton_Click(sender As Object, e As EventArgs) Handles btn_Start.Click
If Not BackgroundWorker1.IsBusy Then
BackgroundWorker1.RunWorkerAsync()
End If
End Sub
Private Sub cancelAsyncButton_Click(sender As Object, e As EventArgs) Handles btn_Cancel.Click
If BackgroundWorker1.WorkerSupportsCancellation = True Then
BackgroundWorker1.CancelAsync()
End If
End Sub
Private Sub backgroundWorker1_DoWork(ByVal sender As Object, ByVal e As DoWorkEventArgs) Handles BackgroundWorker1.DoWork
'Dim worker As BackgroundWorker = TryCast(sender, BackgroundWorker)
For i As Integer = 1 To 10
If Not BackgroundWorker1.CancellationPending Then
System.Threading.Thread.Sleep(500)
BackgroundWorker1.ReportProgress(i * 10)
Else
e.Cancel = True
Exit For
End If
Next
End Sub
Private Sub backgroundWorker1_ProgressChanged(ByVal sender As Object, ByVal e As ProgressChangedEventArgs) Handles BackgroundWorker1.ProgressChanged
resultLabel.Text = (e.ProgressPercentage.ToString() & "%")
End Sub
Private Sub backgroundWorker1_RunWorkerCompleted(ByVal sender As Object, ByVal e As RunWorkerCompletedEventArgs) Handles BackgroundWorker1.RunWorkerCompleted
If e.Cancelled = True Then
resultLabel.Text = "Canceled!"
ElseIf e.Error IsNot Nothing Then
resultLabel.Text = "Error: " & e.[Error].Message
Else
resultLabel.Text = "Done!"
End If
End Sub
The main thing it looked like you were missing was the Handles Event for the Background1.ProgressChanged
I am running a BackgroundWorker, and want to report its progress. In the example below I create a test list which the BackgroundWorker then iterates through. The problem lies in the line 'sender.ReportProgress(i)'. If I have Option Strict on, it does not like my use of 'i' due to Late Binding issues. Is there any alternative way to code this and avoid that issue?
Public Class Form1
Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
' Configuring for Background Workers
Control.CheckForIllegalCrossThreadCalls = False
Dim MyList As New List(Of String)
For a As Integer = 0 To 100
MyList.Add(CStr(a))
Next
End Sub
Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
Dim bgw As New System.ComponentModel.BackgroundWorker
bgw.WorkerReportsProgress = True
bgw.WorkerSupportsCancellation = True
AddHandler bgw.DoWork, AddressOf bgw_DoWork
' I create a BackgroundWorker here rather than add one in the toolbox so that I can specify the Handler and use different Handler routines for different part of a large program.
Button1.Enabled = False
Dim progress As New Progress(bgw)
progress.ShowDialog()
Button1.Enabled = True
End Sub
Private Sub bgw_DoWork(sender As System.Object, e As System.ComponentModel.DoWorkEventArgs)
For i = 0 To MyList.Count -1
Label1.Text = MyList(i)
sender.ReportProgress(i)
System.Threading.Thread.Sleep(200)
Label1.Refresh()
Next
End Sub
End Class
Public Class Progress
Private WithEvents _BGW As System.ComponentModel.BackgroundWorker
Public Sub New(ByVal BGW As System.ComponentModel.BackgroundWorker)
_BGW = BGW
InitializeComponent()
End Sub
Private Sub frmProgress_Shown(sender As Object, e As System.EventArgs) Handles Me.Shown
If Not IsNothing(_BGW) Then
_BGW.RunWorkerAsync()
End If
End Sub
Private Sub _BGW_ProgressChanged(sender As Object, e As System.ComponentModel.ProgressChangedEventArgs) Handles _BGW.ProgressChanged
ProgressBar1.Value = e.ProgressPercentage
Label1.Text = e.ProgressPercentage
End Sub
Private Sub _BGW_RunWorkerCompleted(sender As Object, e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles _BGW.RunWorkerCompleted
Me.Close()
End Sub
End Class
CType(sender, BackgroundWorker).ReportProgress(i)
Also, if you want to do multiple actions with it, then create a local reference variable like this:
Private Sub bgw_DoWork(sender As System.Object, e As System.ComponentModel.DoWorkEventArgs)
Dim bgw As System.ComponentModel.BackgroundWorker = DirectCast(sender, System.ComponentModel.BackgroundWorker)
' ... now you can use "bgw" multiple times below instead of casting each time ...
For i = 0 To MyList.Count -1
Label1.Text = MyList(i)
bgw.ReportProgress(i)
bgw.SomethingElse()
bgw.MoreStuff()
System.Threading.Thread.Sleep(200)
Label1.Refresh()
Next
End Sub
Obviously this isn't necessary in your case, just an FYI...
Hey guys my question is how can I access (update/read) richtextbox in a thread.
I just created a very simple code for you to understand what I am doing. I searched some articles on internet mentioned about invoke, delegate or backgroundworker, hope someone can come and tell me which and how to use. Really thanks.
Imports System.Threading
Public Class form1
Dim flag As Boolean = True
Dim startbtn As Thread
Dim stopbtn As Thread
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
startbtn = New Thread(AddressOf startfuction)
startbtn.Start()
End Sub
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
stopbtn = New Thread(AddressOf stopfunction)
stopbtn.Start()
End Sub
'************** thread 1
Private Sub startfuction()
flag = True
While flag = True
richtextbox1.text = "Your process started" 'error
End While
End Sub
'************** thread 2
Private Sub stopfunction()
flag = False
startbtn.Abort()
MsgBox("You ended the process")
End Sub
End Class
Imports System.Threading
Public Class Form1
Dim flag As Boolean = True
Dim startbtn As Thread
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
startbtn = New Thread(AddressOf startfuction)
startbtn.Start()
End Sub
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
flag = False
MsgBox("You ended the process")
End Sub
'************** thread 1
Private Sub startfuction()
flag = True
While flag = True
Me.Invoke(Sub() RichTextBox1.Text = "Your process started") 'error
End While
Me.Invoke(Sub() RichTextBox1.Text = "Your process stopped") 'error
End Sub
End Class
EDIT 1
Also when running threads, When you goto close your app you could run into problems because your threads will end prematurely..
do something like
Private Sub Form1_FormClosing(sender As Object, e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
flag = False
Application.DoEvents()
End Sub
The problem is that multi threading is not working properly for getting links from webbrowser1.document.links. How can I solve this problem?
Public Class Form1
Dim thread1 As System.Threading.Thread
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
thread1 = New System.Threading.Thread(AddressOf GetLinks)
thread1.Start()
End Sub
Private Sub GetLinks()
For i As Integer = 0 To WebBrowser1.Document.Links.Count - 1
If TextBox1.Text.Length > 0 Then
TextBox1.Text += Environment.NewLine & WebBrowser1.Document.Links(i).ToString
Else
TextBox1.Text = WebBrowser1.Document.Links(i).ToString
End If
Next
End Sub
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
WebBrowser1.Navigate("www.google.com")
Me.CheckForIllegalCrossThreadCalls = False
End Sub
End Class
You can't make a call to one of the controls on the form (in this case, TextBox1 and WebBrowser1) from another thread other than the main thread of the form. You need to use a delegate.
This will do the trick:
Private _iLinks As Integer
Dim thread1 As System.Threading.Thread
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
CheckForIllegalCrossThreadCalls = False
_iLinks = WebBrowser1.Document.Links.Count
thread1 = New System.Threading.Thread(AddressOf GetLinks)
thread1.Start()
End Sub
Private Sub GetLinks()
For i As Integer = 0 To _iLinks - 1
UpdateTextBoxDelegate(i)
Next
End Sub
Private Sub UpdateTextBox(ByVal iLink As Integer)
If TextBox1.Text.Length > 0 Then
TextBox1.Text += Environment.NewLine & WebBrowser1.Document.Links(iLink).ToString
Else
TextBox1.Text += WebBrowser1.Document.Links(iLink).InnerText.ToString()
End If
End Sub
Private Delegate Sub UpdateTextBoxCallback(ByVal iLink As Integer)
Private Sub UpdateTextBoxDelegate(ByVal iLink As Integer)
Try
If Me.InvokeRequired Then
Dim cb As New UpdateTextBoxCallback(AddressOf UpdateTextBox)
Me.Invoke(cb, New Object() {iLink})
Else
UpdateTextBox(iLink)
End If
Catch ex As Exception
MessageBox.Show("There was an error " + ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
End Try
End Sub
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
WebBrowser1.Navigate("http://stackoverflow.com/")
End Sub
why does the FileSystemWatcher fire twice? Is there an easy way to fix it? Surely if I update or edit the text file it should only fire once?
this link here http://weblogs.asp.net/ashben/archive/2003/10/14/31773.aspx says
Events being raised twice - An event will be raised twice if an event handler (AddHander FSW.Created, AddressOf FSW_Created) is
explicitly specified. This is because, by default, the public events
automatically call the respective protected methods (OnChanged,
OnCreated, OnDeleted, OnRenamed). To correct this problem, simply
remove the explicit event handler (AddHandler ...).
What does "remove the explicit event handler" mean?
Imports System.IO
Public Class Form2
Private Sub FileSystemWatcher1_Changed(ByVal sender As System.Object, ByVal e As System.IO.FileSystemEventArgs) Handles FileSystemWatcher1.Changed
'this fires twice
MessageBox.Show("test")
End Sub
Private Sub Form2_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
FileSystemWatcher1.Path = "C:\Users\c\Desktop\test\"
FileSystemWatcher1.NotifyFilter = NotifyFilters.LastAccess Or NotifyFilters.LastWrite Or NotifyFilters.FileName Or NotifyFilters.DirectoryName Or NotifyFilters.CreationTime
FileSystemWatcher1.IncludeSubdirectories = False
FileSystemWatcher1.Filter = "text.txt"
End Sub
End Class
Update:
I have come up with 2 solutions. One uses Threads, and the other doesn't. Take your pick :-).
Without threading:
Imports System.IO
Public Class Form1
Private Sub FileSystemWatcher1_Changed(ByVal sender As System.Object, ByVal e As System.IO.FileSystemEventArgs) Handles FileSystemWatcher1.Changed
Dim watcher As System.IO.FileSystemWatcher = sender
watcher.EnableRaisingEvents = False
'Do work here while new events are not being raised.
MessageBox.Show("Test")
watcher.EnableRaisingEvents = True 'Now we can begin watching for new events.
End Sub
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
FileSystemWatcher1.Path = "C:\Users\c\Desktop\test"
FileSystemWatcher1.NotifyFilter = NotifyFilters.LastWrite
FileSystemWatcher1.IncludeSubdirectories = False
FileSystemWatcher1.Filter = "test.txt"
End Sub
Private Sub FileSystemWatcher_OnChanged(ByVal sender As System.Object, ByVal e As System.EventArgs)
End Sub
End Class
This solution (without threading), sets the watcher.EnableRaisingEvents to False. It is after this point where you would normally process whatever files are affected (or changed). It then sets the EnableRaisingEvents back to True after your work is done.
With threading:
Imports System.IO
Public Class Form1
Private Sub FileSystemWatcher1_Changed(ByVal sender As System.Object, ByVal e As System.IO.FileSystemEventArgs) Handles FileSystemWatcher1.Changed
FileSystemWatcher1.EnableRaisingEvents = False
Threading.Thread.Sleep(250)
FileSystemWatcher1.EnableRaisingEvents = True
MessageBox.Show("test")
End Sub
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
FileSystemWatcher1.Path = "C:\Users\c\Desktop\test"
FileSystemWatcher1.NotifyFilter = NotifyFilters.LastWrite
FileSystemWatcher1.IncludeSubdirectories = False
FileSystemWatcher1.Filter = "test.txt"
End Sub
Private Sub FileSystemWatcher_OnChanged(ByVal sender As System.Object, ByVal e As System.EventArgs)
End Sub
End Class
This solution, although a bit hacky, does work. It disables checking for new changes/events for 250ms and then re-enables checking, based on the assumption that you won't been needing to check for a change every 250ms. I have tried almost everything that I could think of to get a real solution for you but this will work in the meantime.
Check e.ChangeType. I imagine you're getting two different notifications. Perhaps LastAccess and LastModified. In which case, that's the expected behavior.
Today i crashed in FileSystemWatcher and found this site. Suggested Thread.Sleep cannot completely eliminate problem. Tested with fast counter-integer. And is blocking UI. Most problematic is startup, it sliped trough at 5s. Then i set FileSystemWatcher1.EnableRaisingEvents = False immediately in TimerWatcherChanged.Tick and never enabled again... But surprisingly counter still catch up-to 4 events! I would like to share my solution, non-blocking, with adjustable Timer. Feedback is welcome.
Imports System.IO
Imports System.Diagnostics
Public Class Form1
Dim fileName As String
Dim Fsw_counter As Integer
WithEvents TimerWatcherChanged As New Windows.Forms.Timer
WithEvents TimerTest As New Windows.Forms.Timer
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
TimerWatcherChanged.Interval = 100
TimerTest.Interval = 100 : TimerTest.Start()
TextBox1.Text = "C:\Downloads\New Text Document.txt"
TextBox1.SelectionStart = TextBox1.Text.Length
WatcherSetup()
End Sub
Sub WatcherSetup()
fileName = TextBox1.Text
FileSystemWatcher1.IncludeSubdirectories = False
FileSystemWatcher1.Path = Path.GetDirectoryName(fileName)
FileSystemWatcher1.Filter = Path.GetFileName(fileName)
FileSystemWatcher1.NotifyFilter = NotifyFilters.LastWrite
FileSystemWatcher1.EnableRaisingEvents = True
End Sub
Private Sub TextBox1_TextChanged(sender As Object, e As EventArgs) Handles TextBox1.TextChanged
WatcherSetup()
End Sub
Private Sub FileSystemWatcher1_Changed(sender As Object, e As FileSystemEventArgs) Handles FileSystemWatcher1.Changed
If TimerWatcherChanged.Enabled = False Then
TimerWatcherChanged.Enabled = True
Fsw_counter += 1
' ***** Your WATCH Code put here... *****
End If
End Sub
Private Sub TimerWatcherChanged_Tick(sender As Object, e As EventArgs) Handles TimerWatcherChanged.Tick
TimerWatcherChanged.Enabled = False
End Sub
Private Sub TimerTest_Tick(ByVal sender As Object, ByVal e As System.EventArgs) Handles TimerTest.Tick
TextBox2.Text = "Changed: " & Fsw_counter
If TimerWatcherChanged.Enabled = True Then
TextBox2.BackColor = Color.Red
Else
TextBox2.BackColor = Color.LawnGreen
End If
End Sub
End Class