Visual Basic - Wait for webpage to load not working - vb.net

I'm trying to load a website, wait for it to fully load and then display a message box when it's loaded.
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
WebBrowser1.Navigate("https://www.google.com")
Do Until WebBrowser1.ReadyState = 4
Threading.Thread.Sleep(100)
Loop
MsgBox("Loaded")
End Sub
However, when I use this nothing happens, at all despite waiting about 30 seconds. If I remove everything to leave me with...
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
WebBrowser1.Navigate("https://www.google.com")
End Sub
..., It loads fine.

The UI isn't going to load the page because you've tied up the UI thread in an infinite (or at least near infinite) loop.
Instead of waiting for the browser to load, asynchronously respond to the event of the browser loading. Something like this:
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
WebBrowser1.Navigate("https://www.google.com")
End Sub
Private Sub WebBrowser1_DocumentCompleted(ByVal sender As Object, ByVal e As WebBrowserDocumentCompletedEventArgs) Handles WebBrowser1.DocumentCompleted
MsgBox("Loaded")
End Sub
Any time you find yourself wanting to "pause" an application to wait for something to happen, it's highly likely that you need to subscribe to an event when that something happens.

If I'm seeing this right, its due to the fact you're making the main thread stop everytime you're running the check. Couldn't you just add an event handler on the DocumentCompleted event?

Related

Is there a Form event like "Shown" but runs the code every time it is displayed instead of the just first time?

Just noticed in one of my programs that the form event Shown only runs the code when the form is first displayed. Every other time after that it does not run the code. Is there a form event that does what shown does, but every time it is displayed instead of just the first? Or is there a way to get around it? This is the exact same for the Load event too.
Thanks heaps, appreciate any response.
I just tested with this in Form1:
Private f2 As New Form2
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
f2.Show()
End Sub
and this in Form2:
Private Sub Form2_Load(sender As Object, e As EventArgs) Handles MyBase.Load
MessageBox.Show("Form2_Load")
End Sub
Private Sub Form2_VisibleChanged(sender As Object, e As EventArgs) Handles Me.VisibleChanged
If Visible Then
MessageBox.Show("Form2_VisibleChanged")
End If
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Hide()
End Sub
and it worked exactly as expected. Every time I clicked Button1 in Form1, Form2 was displayed. The first time I saw messages for "Form2_Load"and "Form2_VisibleChanged" and on subsequent occasions on for "Form2_VisibleChanged".

finding web page source at desired instance VB.NET

IN CODE: At 1 browser clicks a button and takes a time to load. AT 2 i get source code of page in RichTextBox1. but as page take time to load code 2 starts before completion of 1 because of that i am unable to get the web page source at desired state? what do i do ? i want to get web page source when web browser completely loads after the execution of code 1.
i have tried
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Me.WebBrowser1.Navigate("some website")
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
WebBrowser1.Document.GetElementById("notification_address").SetAttribute("value", TextBox1.Text)
WebBrowser1.Document.Forms(0).InvokeMember("submit") (-----1-----)
RichTextBox1.Text = WebBrowser1.DocumentText (-----2-----)
End Sub
You can use the DocumentCompleted event.
https://msdn.microsoft.com/en-us/library/system.windows.forms.webbrowser.documentcompleted(v=vs.110).aspx?cs-save-lang=1&cs-lang=vb#code-snippet-1
Private Sub DocumentCompleted(ByVal sender As Object, _
ByVal e As WebBrowserDocumentCompletedEventArgs) Handles WebBrowser1.DocumentCompleted
' this is where your code goes RichTextBox1.Text = WebBrowser1.DocumentText (-----2-----)
End Sub

Play sound on Click Event

Can I make a program that plays a sound every time I click on it somewhere? I really need this. Like, in some operating systems, it plays a sound everytime you click on a window.
The examples are shown using the Button_Click Event.
Playing System Sounds
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
My.Computer.Audio.PlaySystemSound( _
System.Media.SystemSounds.Exclamation)
End Sub
Playing Specified Sounds
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
My.Computer.Audio.Play("C:\Mysound.wav", _
AudioPlayMode.BackgroundLoop)
End Sub

Use Tasks/Multi-Thread to load data and show UI

So I am playing with Multi Threading. I have a specific form that takes quiet a while to pop up as it is loading data from file. My idea was to have the data load in the background but still display the form and have a message on the form showing that additional data is loading.
I have everything done, except I am not sure how to get notified the thread is done and is ready to pass me the data as a Dictionary.
This is as far as I have gotten :P
Dim t1 As Task(Of Dictionary(Of String, Double()))
Private Sub cbchannels_SelectedIndexChanged(sender As Object, e As EventArgs) Handles cbchannels.SelectedIndexChanged
t1 = Task(Of Dictionary(Of String, Double())).Factory.StartNew(Function() Load_Data())
End Sub
Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
If t1.IsCompleted Then
data = t1.Result
End If
End Sub
I know that the task has the ability to check if its completed and to get the results
t1.IsCompleted
t1.Result
Is using a timer to continuously check if the task is completed the only way?
And is what I am doing makes sense?
I do not want to use a BackgroundWorker.
That timer is very clever. Fortunately there is a direct was to get notified. You can call ContinueWith on any Task to register a callback that is called when that task completes. This answers your question as asked.
Instead you should be looking into async and await. Running background work in UI apps has gotten a lot easier with C# 5.
While it's not the only way, the simplest option may be to use a BackgroundWorker. You call RunWorkerAsync to set it off and do the work in the DoWork event handler. When you're done, assign the data to the e.Result property. You can then get that back on the UI thread in the RunWorkerCompleted event handler. E.g.
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
BackgroundWorker1.RunWorkerAsync()
End Sub
Private Sub BackgroundWorker1_DoWork(sender As Object, e As DoWorkEventArgs) Handles BackgroundWorker1.DoWork
Dim table As DataTable = GetData()
e.Result = table
End Sub
Private Sub BackgroundWorker1_RunWorkerCompleted(sender As Object, e As RunWorkerCompletedEventArgs) Handles BackgroundWorker1.RunWorkerCompleted
Dim table = DirectCast(e.Result, DataTable)
'Use table here.
End Sub

Wait for the browser to load COMPLETELY (or extract Captcha from website)

I have a big problem and im trying to fix it for days and its just not working.
I want to make a program that extracts a Captcha from a website and then show it to the user, the user solves it and then the programm checks if the code is right or wrong.
The problem is that the event "Webbrowser1_DocumenCompleted" doesn't wait untill the scripts are COMPLETELY loaded. So, sometimes the code shows, but and sometimes not.. its like a 50/50 chance..
Here is my code so far:
Imports System.Text
Imports System.Text
Public Class Form1
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
WebBrowser1.Navigate("http://minecraft-server.eu/vote/index/2421")
End Sub
Private Sub WebBrowser1_DocumentCompleted(ByVal sender As System.Object, ByVal e As System.Windows.Forms.WebBrowserDocumentCompletedEventArgs) Handles WebBrowser1.DocumentCompleted
Try
Dim htmlDocument As HtmlDocument = Me.WebBrowser1.Document
Dim htmlElementCollection As HtmlElementCollection = htmlDocument.Images
Dim ImagesFound As Integer = 0
For Each htmlElement As HtmlElement In htmlElementCollection
Dim imgUrl As String = htmlElement.GetAttribute("src")
If imgUrl.Contains("google.com/recaptcha/api/image?") Then
ImagesFound += 1
Select Case ImagesFound
Case 1
WebBrowser2.Navigate(imgUrl)
End Select
End If
Next
Catch ex As Exception
End Try
End Sub
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
WebBrowser1.Document.GetElementById("recaptcha_response_field").SetAttribute("value", tbText.Text)
WebBrowser1.Document.GetElementById("minecraftname").SetAttribute("value", minecraftnamebox.text)
WebBrowser1.Document.GetElementById("button").InvokeMember("click")
End Sub
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
Dim sQuelltext As String = WebBrowser1.DocumentText.ToString
If sQuelltext.Contains("Captcha Falsch") Then
MsgBox("Wrong verification Code! Try again.")
Application.Restart()
Else
End
End If
End Sub
Private Sub Button3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button3.Click
Application.Restart()
End Sub
End Class
You problem is understandable. Because the browser has no clue that there's more stuff to be executed. When a script has finished loading, it doesn't mean that no more work to be done. It could be that a script waits 200 milliseconds and then does something, so there's no generic way of determining when a page has 'fully loaded'.
The DocumentCompleted event fires when the whole page has been downloaded, and all scripts, images and other dependencies have loaded. So, the DocumentCompleted does fire at the right time.
However, the captcha seems to be created some time after the document has completed loading, as said, the browser has no clue that he's supposed to wait on this. We can confirm this theory by visiting the page in our browser:
http://minecraft-server.eu/vote/index/2421
When the browser hides the spinning icon (which indicates loading) it takes about 500 more milliseconds for the captcha to actually be visible. You obviously can't rely on 500 milliseconds because it all depends on the connection.
The WebBrowser component does expose the FileDownload event, which occurs everytime a file is downloaded. This could be an image that's on the web page, anything. The only problem is that when the event fires, there's no way of know what file the event fired for.
The easiest solution in this case is to check whether the captcha has been loaded, each time the FileDownload event fires. You should prevent checking for the captcha in the FileDownload event before the document was completely loaded. So, before iterating over all HTML elements, check whether the document was completely loaded.
Try checking if WebBrowser1.ReadyState equals WebBrowserReadyState.Complete.