vb.net - How to get webbrowser InnerHtml under multithread - vb.net

I use SetApartmentState in webbrowser:
Private Sub frmMain_Shown(sender As Object, e As EventArgs) Handles Me.Shown
Dim th As System.Threading.Thread = New Threading.Thread(AddressOf Task_A)
th.SetApartmentState(ApartmentState.STA)
th.Start()
End Sub
Public Sub Task_A()
Dim frmBuild = New NewForm()
Dim WebBrowser1 = New WebBrowser()
Application.Run(frmBuild)
frmBuild.Controls.Add(WebBrowser1)
WebBrowser1.CreateControl()
End Sub
Private Delegate Function GetInnerHTMLCallBack() As String
Private Function GetInnerHTML() As String
If WebBrowser1.InvokeRequired Then
Return CStr(WebBrowser1.Invoke(New GetInnerHTMLCallBack(AddressOf GetInnerHTML)))
Else
Return WebBrowser1.Document.Body.InnerHtml
End If
End Function
Dim innerHTML As String = GetInnerHTML()
frmMain.textbox1.text=innerHTML
Dim docs As mshtml.HTMLDocument = WebBrowser1.Document.DomDocument
I get nothing, how can I get or set string in cross threading?
I am very poor in multi-threading.

Related

Passing data through form with showdialog but without closing event

I have a first form (form_notice_hashtag) called like this:
Public Sub afficher_hashtag(hashtag As String, plateforme_hashtag As String)
Dim form_notice_hashtag_1 As New form_notice_hashtag
form_notice_hashtag_1.StartPosition = FormStartPosition.CenterScreen
form_notice_hashtag_1.Show()
End Sub
In form_notice_hashtag_1, i have a button calling a 2nd form (form_recherche_thesaurus) like this:
Private Sub hashtag_thesaurus_search_button_Click(sender As Object, e As EventArgs) Handles hashtag_thesaurus_search_button.Click
Dim form_recherche_thesaurus_1 As New form_recherche_thesaurus With {
.StartPosition = FormStartPosition.Manual,
.Location = New Point(Me.Left + Me.Width, Me.Top)
}
form_recherche_thesaurus_1.ShowDialog(Me)
End Sub
In form_recherche_thesaurus, i have a datagridview listing some words. The user can select one word, then by clicking a button in form_recherche_thesaurus, the word which will be added to a textbox in form_notice_hashtag
Private Sub thesaurus_ok_button_Click(sender As Object, e As EventArgs) Handles thesaurus_ok_button.Click
Dim list_terms_array As String()
Select Case Owner.Name.ToString
Case "form_notice_hashtag"
list_terms_array = Split(Remove_Duplicates_From_Strings_With_SemiColon(form_notice_hashtag.hashtag_descripteurs_txtbox.Text & ";" & selected_term), ";")
form_notice_hashtag.hashtag_descripteurs_txtbox.Text = (String.Join(";", list_terms_array.Where(Function(s) Not String.IsNullOrEmpty(s))))
End Select
End Sub
I used a select because this mechanism would be used in the same way with other forms than form_notice_hashtag.
Problem: the textbox in form_notice_hashtag is not filled with the selected keywords. I guess it's because of the way form_notice_hashtag is called.
I can't use the solution as explained here Send values from one form to another form because i understood (maybe badly) that this solution works only if the 2nd form (form_recherche_thesaurus in my case) is closed (i.e closing was the trigger) which i don't want.
How can I proceed?
Thanks to jmcilhinney and this page of his blog, here is the solution that allows to transfer several data from a called form (form_recherche_thesaurus) to a calling form (form_notice_hashtag) without closing the called form .
Public Class form_notice_hashtag
Private WithEvents form_recherche_thesaurus_1 As form_recherche_thesaurus
Private selected_thesaurus_term As String
Private Sub form_recherche_thesaurus_1_TextBoxTextChanged(sender As Object, e As EventArgs) Handles form_recherche_thesaurus_1.TextBoxTextChanged
Dim list_terms_array As String() = Split(Remove_Duplicates_From_Strings_With_SemiColon(Me.hashtag_descripteurs_txtbox.Text & ";" & form_recherche_thesaurus_1.selected_term), ";")
Me.hashtag_descripteurs_txtbox.Text = (String.Join(";", list_terms_array.Where(Function(s) Not String.IsNullOrEmpty(s))))
End Sub
Private Sub hashtag_thesaurus_search_button_Click(sender As Object, e As EventArgs) Handles hashtag_thesaurus_search_button.Click
Dim form_recherche_thesaurus_1 As New form_recherche_thesaurus With {
.StartPosition = FormStartPosition.Manual,
.Location = New Point(Me.Left + Me.Width, Me.Top)
}
If Me.form_recherche_thesaurus_1 Is Nothing OrElse Me.form_recherche_thesaurus_1.IsDisposed Then
Me.form_recherche_thesaurus_1 = New form_recherche_thesaurus With {
.StartPosition = FormStartPosition.Manual,
.Location = New Point(Me.Left + Me.Width, Me.Top)
}
Me.form_recherche_thesaurus_1.Show()
End If
Me.form_recherche_thesaurus_1.Activate()
End Sub
End Class
Public Class form_recherche_thesaurus
Public Event TextBoxTextChanged As EventHandler
Private term_thesaurus As String
Public Property selected_term() As String
Get
Return term_thesaurus
End Get
Set(ByVal value As String)
term_thesaurus = value
End Set
End Property
Private Sub thesaurus_ok_button_Click(sender As Object, e As EventArgs) Handles thesaurus_ok_button.Click
Dim list_terms_array As String()
Me.selected_term = Me.thesaurus_search_results_datagrid.Item(0, Me.thesaurus_search_results_datagrid.CurrentRow.Index).Value
Me.DialogResult = DialogResult.OK
RaiseEvent TextBoxTextChanged(Me, EventArgs.Empty)
End Sub

The GUI is not moving properly

I'm doing a little widget that shows the price of bitcoin using Binance API here
I'm not using Json format as I Just need to parse one string, eventhough I know many of you will say to use json. Anyway, I want to keep the software as simple as possible, but there is a little problem.
I'm downloading the source with webclient and Updating it using a timer.
I think I'm doing a mistake creating every time the new webclient because when I want to move the form, Is not properly mooving even if its not freezing.
The code I'm using is:
Private Sub webclientbtc()
Dim wc As New Net.WebClient
Dim WBTC As IO.Stream = Nothing
wc.Encoding = Encoding.UTF8
WBTC = wc.OpenRead("https://api.binance.com/api/v1/ticker/24hr?symbol=BTCEUR")
Dim btc As String
Using rd As New IO.StreamReader(WBTC)
btc = rd.ReadToEnd
End Using
'---------BTC PRICE---------'
Dim textBefore As String = """lastPrice"":"""
Dim textAfter As String = ""","
Dim startPosition As Integer = btc.IndexOf(textBefore)
startPosition += textBefore.Length
Dim endPosition As Integer = btc.IndexOf(textAfter, startPosition)
Dim textFound As String = btc.Substring(startPosition, endPosition - startPosition)
Dim dNumber As Double = Val(textFound.ToString)
Label1.Text = dNumber.ToString("n2")
'-------------------------------------'
Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
webclientbtc()
End Sub
Timer interval is on 1000 ms, which is great to keep me update.
Any idea on how I can avoid the creations of new webclient at every update?
Thanks
Simplified, and using TAP:
Private wc as New WebClient()
Private Async Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
Dim s = Await wc.DownloadStringTaskAsync("https://api.binance.com/api/v1/ticker/24hr?symbol=BTCEUR")
Dim d = JsonConvert.DeserializeObject(Of Dictionary(Of String, String))(s)
Label1.Text = d("lastPrice")
End Sub
You need to reference newtonsoft json package and imports it, as well as imports system.collections.generic
If the answer by Caius Jard is too good, you can avoid the use of a JSON deserialiser by using a regex:
Imports System.Net
Imports System.Text.RegularExpressions
Public Class Form1
Dim tim As New Timer()
Private Async Sub UpdateBtc(sender As Object, e As EventArgs)
' temporarily disable the timer in case the web request takes a long time
tim.Enabled = False
' using New Uri() makes sure it is a proper URI:
Dim url = New Uri("https://api.binance.com/api/v1/ticker/24hr?symbol=BTCEUR")
Dim rawJson As String
Using wb As New WebClient()
rawJson = Await wb.DownloadStringTaskAsync(url)
End Using
Dim re = New Regex("""lastPrice"":\s*""([0-9.-]+)""")
Dim lastPrice = re.Match(rawJson)?.Groups(1)?.Value
Dim p As Decimal
lblLastPrice.Text = If(Decimal.TryParse(lastPrice, p), p.ToString("N2"), "Fetch error.")
tim.Enabled = True
End Sub
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
UpdateBtc(Nothing, EventArgs.Empty)
tim.Interval = 3000
AddHandler tim.Tick, AddressOf UpdateBtc
tim.Start()
End Sub
Private Sub Form1_FormClosing(sender As Object, e As FormClosingEventArgs) Handles MyBase.FormClosing
If tim IsNot Nothing Then
tim.Stop()
RemoveHandler tim.Tick, AddressOf UpdateBtc
tim.Dispose()
End If
End Sub
End Class
There's no need to re-use the WebClient, creating it is not what is taking up the time.
I prefer to instantiate timers myself: there is no requirement to do so.
It is better to use descriptive names for controls: "Label1" tells you nothing.

How to wait for get request without freezing client

I have a simple button which sends a get request to retrieve a txt file on my website. Problem is it freezes the application while retrieving the info. How can I make it so the application doesn't freeze while waiting for the result?
Private Sub cmd_ClickMe_Click(sender As Object, e As EventArgs) Handles cmd_ClickMe.Click
Dim request As String = String.Format("http://www.*****/database/test.txt")
Dim webClient As New System.Net.WebClient
Dim result As String = webClient.DownloadString(request)
MessageBox.Show(result)
End Sub
I've also tried the following but it doesn't work (says "webClient.DownloadStringAsync(myUri)" does not produce a value:
Private Sub cmd_ClickMe_Click_1(sender As Object, e As EventArgs) Handles cmd_ClickMe.Click
Dim request As String = String.Format("http://www.****.com/database/test.txt")
Dim webClient As New System.Net.WebClient
Dim myUri As Uri = New Uri(request)
Dim result As String = webClient.DownloadStringAsync(myUri)
MessageBox.Show(result)
End Sub
Use DownloadStringAsync(Uri) instead of the DownloadString(uri).
The DownloadStringAsync method does not block the calling thread.
Here is an example how to use it:
Dim wc As New WebClient
' Specify that you get alerted
' when the download completes.
AddHandler wc.DownloadStringCompleted, AddressOf AlertStringDownloaded
Dim uri As New Uri("http:\\changeMe.com") 'Pass the URL to here. This is just an example
wc.DownloadStringAsync(uri)
End Sub
Public Shared Sub AlertStringDownloaded(ByVal sender As Object, ByVal e As DownloadStringCompletedEventArgs)
' If the string request went as planned and wasn't cancelled:
If e.Cancelled = False AndAlso e.Error Is Nothing Then
Dim myString As String = CStr(e.Result) 'Use e.Result to get the String
MessageBox.Show(myString)
End If
End Sub

Trying to change a timer once a button is pressed

I have a check going every 60 seconds, if the alarm is true it will open form2 play a song etc.
but the button on form2 should set the waittimer = 180000 which should make the next check occur half an half an hour later.
I'm not used to using timers, what am I doing wrong?
Public Class Form1
Public Property waittimer As Integer
Public Property playsong As Boolean = True
Private WithEvents Tmr As New Timer
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
If (Process.GetProcessesByName(Process.GetCurrentProcess.ProcessName).Length > 1) Then
Application.Exit()
End If
Tmr.Enabled = False
Tmr.Interval = TimeSpan.FromSeconds(60).TotalMilliseconds
BackgroundWorker1.RunWorkerAsync()
End Sub
Private Sub NotifyIcon1_MouseDoubleClick(sender As Object, e As MouseEventArgs) Handles NotifyIcon1.MouseDoubleClick
playsong = False
Try
' Create a request for the URL.
Dim request As WebRequest = _
WebRequest.Create("http://example.com/example.aspx")
' If required by the server, set the credentials.
request.Credentials = CredentialCache.DefaultCredentials
' Get the response.
Dim response As WebResponse = request.GetResponse()
' Display the status.
Console.WriteLine(CType(response, HttpWebResponse).StatusDescription)
' Get the stream containing content returned by the server.
Dim dataStream As Stream = response.GetResponseStream()
' Open the stream using a StreamReader for easy access.
Dim reader As New StreamReader(dataStream)
' Read the content.
Dim responseFromServer As String = reader.ReadToEnd()
' Display the content.
Console.WriteLine(responseFromServer)
' Clean up the streams and the response.
reader.Close()
response.Close()
Dim responseArray() As String
responseArray = Split(responseFromServer, "|")
Dim D As New Data
D.maxcalls = responseArray(0)
D.cph = responseArray(1)
D.mht = responseArray(2)
D.alarm = responseArray(3)
Form2.startsong(D)
Catch ex As Exception
End Try
playsong = True
End Sub
Private Sub ExitToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles ExitToolStripMenuItem.Click
Application.Exit()
End
End Sub
Private Sub BackgroundWorker1_DoWork(sender As Object, e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
Try
If waittimer = 180000 Then
Tmr.Interval = waittimer
Tmr.Start()
waittimer = 60000
Else
waittimer = 60000
End If
' Create a request for the URL.
Dim request As WebRequest = _
WebRequest.Create("http://example.com/example.aspx")
' If required by the server, set the credentials.
request.Credentials = CredentialCache.DefaultCredentials
' Get the response.
Dim response As WebResponse = request.GetResponse()
' Display the status.
Console.WriteLine(CType(response, HttpWebResponse).StatusDescription)
' Get the stream containing content returned by the server.
Dim dataStream As Stream = response.GetResponseStream()
' Open the stream using a StreamReader for easy access.
Dim reader As New StreamReader(dataStream)
' Read the content.
Dim responseFromServer As String = reader.ReadToEnd()
' Display the content.
Console.WriteLine(responseFromServer)
' Clean up the streams and the response.
reader.Close()
response.Close()
Dim responseArray() As String
responseArray = Split(responseFromServer, "|")
Dim D As New Data
D.maxcalls = responseArray(0)
D.cph = responseArray(1)
D.mht = responseArray(2)
D.alarm = responseArray(3)
D.forcealarm = False
e.Result = D
Catch ex As Exception
Dim D As New Data
D.maxcalls = 404
D.cph = 404
D.mht = 404
D.alarm = True
D.forcealarm = True
e.Result = D
End Try
Tmr.Interval = waittimer
End Sub
Private Sub BackgroundWorker1_RunWorkerCompleted(sender As Object, e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles BackgroundWorker1.RunWorkerCompleted
If Not IsNothing(e.Result) Then
Dim strtime As String
Dim englandtime = System.TimeZoneInfo.ConvertTime(Now, TimeZoneInfo.FindSystemTimeZoneById("UTC"))
strtime = DatePart(Microsoft.VisualBasic.DateInterval.Hour, englandtime) & DatePart(Microsoft.VisualBasic.DateInterval.Minute, englandtime)
Dim D As Data = DirectCast(e.Result, Data)
If D.forcealarm = True Then
Form2.startsong(D)
End If
If D.alarm Then
If strtime < 730 And strtime > 0 Then
Else
Form2.startsong(D)
End If
End If
End If
Tmr.Start()
End Sub
Private Sub Tmr_Tick(sender As Object, e As System.EventArgs) Handles Tmr.Tick
Tmr.Stop()
BackgroundWorker1.RunWorkerAsync()
End Sub
End Class
Public Class Data
Public Property maxcalls As Integer
Public Property cph As Integer
Public Property mht As Integer
Public Property alarm As Boolean
Public Property forcealarm As Boolean
End Class
Form2
Public Class Form2
Public audio As New AudioFile(My.Application.Info.DirectoryPath & "\Help.mp3")
Public Sub startsong(ByVal D As Data)
Me.Show()
MHTvalue.Text = D.mht.ToString
Maxcallsvalue.Text = D.maxcalls
CPHvalue.Text = D.cph
If Form1.playsong = True Then
audio.Play()
End If
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
' Me.Close()
audio.Stop()
Form1.waittimer = 180000
End Sub
Private Sub Form2_Closing(sender As Object, e As EventArgs) Handles MyBase.Load
audio.Stop()
Form1.waittimer = 180000
End Sub
Private Sub Form2_Minimize(sender As Object, e As EventArgs) Handles MyBase.Load
audio.Stop()
Form1.waittimer = 180000
End Sub
Thats probably because your timer on the original form1 instance never get re configured by your code. You are instead setting a timer on a new copy of form 1 that is not running (showing).
You need to get the running instance of form1 that you originally opened. A technique I use for something like this, is to tag my form I will be looking for, and then stepping through the form instances currently running, getting my form via its tag, setting that found form equal to the object I am working with, and THEN use the properties/methods of that form.
Set your form1's tag to "myTag".
Then on form 2:
For Each f As Form In My.Application.OpenForms
If Not f.InvokeRequired Then
'Can access the form directly.
If f.Tag = "myTag" Then
'this is my form
Dim fcast As New form1
fcast = f
fcast.<---- use your methods / properties...
End If
End If
Next
Just change:
Public Property waittimer As Integer
To:
Public Property waittimer As Integer
Get
Return Tmr.Interval
End Get
Set(value As Integer)
If value > 0 Then
Tmr.Interval = value
End If
End Set
End Property
You were changing the waittimer value, but not the actual Interval() of the Timer as well. This links the two together.

UI freezes on different thread

I've tried elsewhere but nothing came of it. Basically i want the image to show up in the picturebox.
My code:
Dim ScreenReceiverClient As New TcpClient
Dim ScreenReceiverServer As New TcpListener(ScreenReceiverPort)
Dim ScreenReceiverListening As New Thread(AddressOf ScreenListen)
Dim GetScreen As New Thread(AddressOf ReceiveScreen)
Private Sub ReceiveScreen()
While ScreenReceiverClient.Connected = True
Call New Action(AddressOf ChangeImage).BeginInvoke(Nothing, Nothing)
End While
End Sub
Private Sub ChangeImage()
Dim bf As New BinaryFormatter
PictureBox1.Image = bf.Deserialize(ScreenReceiverClient.GetStream)
End Sub
Private Sub ScreenListen()
While ScreenReceiverClient.Connected = False
ScreenReceiverServer.Start()
ScreenReceiverClient = ScreenReceiverServer.AcceptTcpClient
End While
GetScreen.Start()
End Sub
ChangeImage() is supposed to be called on the UI thread instead of the ScreenReceiverListening thread, but the UI just freezes. Please help me!
You need to call the Method asynchronously:
http://msdn.microsoft.com/de-de/library/2e08f6yc(v=vs.110).aspx?cs-save-lang=1&cs-lang=vb#code-snippet-1
Another easy way is, to use a timer:
Private Sub ScreenListen()
While ScreenReceiverClient.Connected = False
ScreenReceiverServer.Start()
ScreenReceiverClient = ScreenReceiverServer.AcceptTcpClient
End While
t1.Interval = 1
t1.Start()
End Sub
Private WithEvents t1 As Windows.Forms.Timer
Private Sub t1_Tick(sender As Object, e As EventArgs) Handles t1.Tick
t1.Stop()
ReceiveScreen()
End Sub