InvokeMember("click") does not trigger WebBrowser.DocumentCompleted event - vb.net

This old unresolved question seems to relate most to my issue WebBrowser control not responding to InvokeMember("click")
The main difference is where the conversation petered out, my webpage does respond to ContentPlaceHolder1_btnComtrsView.click() correctly, where in the original question it did not.
I am trying to pull up a lat/long result after clicking the "View" button after entering in a value for COMTRS (use "M11S19E20" for example): https://www.earthpoint.us/TownshipsCaliforniaSearchByDescription.aspx
I've got the 2 separate document completed event handlers working correctly and all of that. So is it possible to handle the event of the document updating after clicking view? My code does work if I just click once to load the page and click, and a second time to pull the data out.
WebBrowserTRS.ScriptErrorsSuppressed = True
AddHandler WebBrowserTRS.DocumentCompleted, AddressOf ClickViewButton
WebBrowserTRS.Navigate("https://www.earthpoint.us/TownshipsCaliforniaSearchByDescription.aspx")
Private Sub ClickViewButton(sender As Object, e As WebBrowserDocumentCompletedEventArgs)
If e.Url.ToString() = "about:blank" Then Return
RemoveHandler WebBrowserTRS.DocumentCompleted, AddressOf ClickViewButton
Dim trsDoc As HtmlDocument = WebBrowserTRS.Document
Dim elem_Input_Submit As HtmlElement = trsDoc.GetElementById("ContentPlaceHolder1_btnComtrsView")
trsDoc.GetElementById("ContentPlaceHolder1_Comtrs").InnerText = _comtrs
AddHandler WebBrowserTRS.DocumentCompleted, AddressOf GetLatLong
elem_Input_Submit.InvokeMember("click")
End Sub
Private Sub GetLatLong(sender As Object, e As WebBrowserDocumentCompletedEventArgs)
RemoveHandler WebBrowserTRS.DocumentCompleted, AddressOf GetLatLong
Dim trsDoc As HtmlDocument = WebBrowserTRS.Document
Dim centroidFound As Boolean = False
For Each el As HtmlElement In trsDoc.GetElementsByTagName("tr")
Dim val As String
For Each el1 As HtmlElement In el.GetElementsByTagName("TD")
val = el1.InnerText
If val IsNot Nothing AndAlso val.Contains("Centroid") Then
centroidFound = True
' ...
WebBrowserTRS = New WebBrowser
Return
End If
Next
Next
If Not centroidFound Then
MsgBox("Unable to parse the township and range.",
MsgBoxStyle.Information, "Error in location lookup")
End If
Cursor = Cursors.Default
toolstripViewMap.Enabled = True
End Sub

Related

VB.NET | Cannot duplicate tabs properly

I'm trying to create a browser in VB.NET, but I'm having problems to create a button that can "duplicate tabs" in my tabcontrol (called Child_TabControl). Well, I have this code and it seems to works fine in the first tab, but when I try to click on the duplicate button in the generated tab, it duplicates again the URL in the first tab. Anyone can help me to solve this?
Private Async Sub Btn_Duplicate_Click(sender As Object, e As EventArgs) Handles Btn_Duplicate.Click
Dim newTab As New TabPage
Dim child_header As New Tabs_Child_Header
Dim browser As New WebView2
'Events
Await browser.EnsureCoreWebView2Async
AddHandler browser.CoreWebView2.NewWindowRequested, AddressOf Browser_NewWindowRequested
AddHandler browser.CoreWebView2.NavigationCompleted, Sub()
child_header.Text_Url.Text = browser.Source.AbsoluteUri
End Sub
AddHandler child_header.Btn_Back.Click, Sub()
browser.GoBack()
End Sub
AddHandler child_header.Btn_Foward.Click, Sub()
browser.GoForward()
End Sub
AddHandler child_header.Btn_Update.Click, Sub()
browser.Reload()
End Sub
AddHandler child_header.Btn_Duplicate.Click, AddressOf Btn_Duplicate_Click
'Load Child
Child_TabControl.TabPages.Add(newTab)
child_header.TopLevel = False
child_header.Visible = True
child_header.Dock = DockStyle.Fill
newTab.Controls.Add(child_header)
'Child_TabControl.SelectTab(newTab)
'Load Webview
newTab.Text = Child_TabControl.SelectedTab.Text
child_header.Panel_Navigate.Controls.Add(browser)
browser.Dock = DockStyle.Fill
browser.Visible = True
browser.Source = New Uri(Text_Url.Text)
End Sub
I don't know how to reference (as Me) to my control Tabs_Child_Header dinamically created previously.

VB.net DownloadDataAsync to MemoryStream not working

I have the following code to load a picture from the internet directly into my picturebox (from memory):
PictureBox1.Image = New Bitmap(New IO.MemoryStream(New Net.WebClient().DownloadData("LINK")))
The problem here is that my application freezes while the WebClient is downloading, so I thought I would use DownloadDataAsync
However, using this code doesnt work at all:
PictureBox1.Image = New Bitmap(New IO.MemoryStream(New Net.WebClient().DownloadDataAsync(New Uri("LINK"))))
It returns the error "Expression does not produce a value"
As the error message states, you cannot simply pass the DownloadDataAsync as MemoryStream parameter, since DownloadDataAsync is a Sub whereas DownloadData is a function returning Bytes().
In order to use DownloadDataSync, check out sample code below:
Dim wc As New Net.WebClient()
AddHandler wc.DownloadDataCompleted, AddressOf DownloadDataCompleted
AddHandler wc.DownloadProgressChanged, AddressOf DownloadProgressChanged ' in case you want to monitor download progress
wc.DownloadDataAsync(New uri("link"))
Below are the event handlers:
Sub DownloadDataCompleted(sender As Object, e As DownloadDataCompletedEventArgs)
' If the request was not canceled and did not throw
' an exception, display the resource.
If e.Cancelled = False AndAlso e.Error Is Nothing Then
PictureBox1.Image = New Bitmap(New IO.MemoryStream(e.Result))
End If
End Sub
Sub DownloadProgressChanged(sender As Object, e As DownloadProgressChangedEventArgs)
' show progress using :
' Percent = e.ProgressPercentage
' Text = $"{e.BytesReceived} of {e.TotalBytesToReceive}"
End Sub

webbrowser auto navigation event

I am using webbrowser to navigate to a website then automating the login. Everything works perfectly up until the point of the comment "Navigating Event" After entering one credential it will login and navigate to another website. After the event none of the code will work as it is not picking up the new site. I am using a waitforpageload() function to let me know when it is completed loading however when I check the url it is still pointing to the original site. Any ideas why it would be doing this and how to possibly get around it?
Private Property pageready As Boolean = False
webBrowser1.Navigate("https://www.lamedicaid.com/sprovweb1/provider_login/provider_login.asp")
waitforpageload()
Dim allelements As HtmlElementCollection = webBrowser1.Document.All
For Each webpageelement As HtmlElement In allelements
'NPI #
If webpageelement.GetAttribute("name") = "Provider_Id" Then
webpageelement.SetAttribute("value", "xxxxxx")
End If
'Clicking enter to input NPI
If webpageelement.GetAttribute("name") = "submit1" Then
webpageelement.InvokeMember("focus")
webpageelement.InvokeMember("click")
waitforpageload()
End If
'Navigation event happens here
'Entering username
If webpageelement.GetAttribute("name") = "Login_Id" Then
webpageelement.SetAttribute("value", "xxxxxxx")
End If
'Entering Password
If webpageelement.GetAttribute("name") = "Password" Then
webpageelement.SetAttribute("value", "xxxxxxxxx")
End If
'logging in
If webpageelement.GetAttribute("name") = "submit_button" Then
webpageelement.InvokeMember("focus")
webpageelement.InvokeMember("click")
waitforpageload()
End If
#Region "Page Loading Functions"
Private Sub waitforpageload()
AddHandler webBrowser1.DocumentCompleted, New WebBrowserDocumentCompletedEventHandler(AddressOf PageWaiter)
While Not pageready
Application.DoEvents()
End While
pageready = False
End Sub
Private Sub PageWaiter(ByVal sender As Object, ByVal e As WebBrowserDocumentCompletedEventArgs)
If webBrowser1.ReadyState = WebBrowserReadyState.Complete Then
pageready = True
RemoveHandler webBrowser1.DocumentCompleted, New WebBrowserDocumentCompletedEventHandler(AddressOf PageWaiter)
End If
End Sub
#End Region
Please, for the love of god, get rid of that waitforpageload() function! Using Application.DoEvents() is BAD PRACTICE and in a loop like that, will utilize 100% of your CPU!
The person who originally wrote that function (it's from another Stack Overflow post) clearly didn't know what he/she was doing at the time. Using Application.DoEvents() creates more problems than it solves, and should NEVER be used in anyone's code (it exists mostly because it is used by internal methods).
Refer to: Keeping your UI Responsive and the Dangers of Application.DoEvents for more info.
The WebBrowser has a dedicated DocumentCompleted event that is raised every time a page (or part of a page, such as an iframe) has been completely loaded.
To make sure that the page really is fully loaded, subscribe to the DocumentCompleted event and check if the ReadyState property is equal to WebBrowserReadyState.Complete.
To be able to run code more "dynamically" when the DocumentCompleted event is raised you can utilize lambda expressions as a way of creating inline methods.
In your case they can be used like this:
'Second step (these must always be in descending order since the first step must be able to reference the second, and so on).
Dim credentialHandler As WebBrowserDocumentCompletedEventHandler = _
Sub(wsender As Object, we As WebBrowserDocumentCompletedEventArgs)
'If the WebBrowser HASN'T finished loading, do not continue.
If webBrowser1.ReadyState <> WebBrowserReadyState.Complete Then Return
'Remove the event handler to avoid this code being called twice.
RemoveHandler webBrowser1.DocumentCompleted, credentialHandler
'Entering username
If webpageelement.GetAttribute("name") = "Login_Id" Then
webpageelement.SetAttribute("value", "xxxxxxx")
End If
'Entering Password
If webpageelement.GetAttribute("name") = "Password" Then
webpageelement.SetAttribute("value", "xxxxxxxxx")
End If
'logging in
If webpageelement.GetAttribute("name") = "submit_button" Then
webpageelement.InvokeMember("focus")
webpageelement.InvokeMember("click")
End If
End Sub
'First step.
Dim loginHandler As WebBrowserDocumentCompletedEventHandler = _
Sub(wsender As Object, we As WebBrowserDocumentCompletedEventArgs)
'If the WebBrowser hasn't finished loading, do not continue.
If webBrowser1.ReadyState <> WebBrowserReadyState.Complete Then Return
'Remove the event handler to avoid this code being called twice.
RemoveHandler webBrowser1.DocumentCompleted, loginHandler
Dim allelements As HtmlElementCollection = webBrowser1.Document.All
For Each webpageelement As HtmlElement In allelements
'NPI #
If webpageelement.GetAttribute("name") = "Provider_Id" Then
webpageelement.SetAttribute("value", "xxxxxx")
'-- Why would you even wait in here?? There's no reason for you to wait after only changing an attribute since nothing is loaded from the internet.
End If
'Clicking enter to input NPI
If webpageelement.GetAttribute("name") = "submit1" Then
'Adding the event handler performing our next step.
AddHandler webBrowser1.DocumentCompleted, credentialHandler
webpageelement.InvokeMember("focus")
webpageelement.InvokeMember("click")
End If
Next
End Sub
'Add the event handler performing our first step.
AddHandler webBrowser1.DocumentCompleted, loginHandler
webBrowser1.Navigate("https://www.lamedicaid.com/sprovweb1/provider_login/provider_login.asp")
Now every time you need to wait for the document/website to be fully loaded, just declare a new lambda and add it as an event handler to DocumentCompleted:
Dim thirdStepHandler As WebBrowserDocumentCompletedEventHandler = _
Sub(wsender As Object, we As WebBrowserDocumentCompletedEventArgs)
'If the WebBrowser hasn't finished loading, do not continue.
If webBrowser1.ReadyState <> WebBrowserReadyState.Complete Then Return
'Remove the event handler to avoid this code being called twice.
RemoveHandler webBrowser1.DocumentCompleted, thirdStepHandler
'Your goes code here...
End Sub
'To wait until performing the next step (be sure to do this BEFORE navigating):
AddHandler webBrowser1.DocumentCompleted, thirdStepHandler

SelectionChanged event occurs more times than it should

I have grid and those grid is populate on Form's load event. At the end line of that event i am hooking method handler for my SelectionChanged event of this grid. I want to get current selected row's zero cell's 1 value. Unfortunately when i run program my SelectionChanged event method handler is called infinite times... And i have no idea why is that.
So its basically like this:
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
some code which populating data to grid...
'here hooking up method after data is there already to not fire it up during grid population
AddHandler gridArtikels.SelectionChanged, AddressOf gridArtikels_SelectionChanged
End Sub
and this is event handler method itself:
Private Sub gridArtikels_SelectionChanged(sender As Object, e As GridEventArgs)
RemoveHandler gridArtikels.SelectionChanged, AddressOf gridArtikels_SelectionChanged
If gridArtikels.PrimaryGrid.Rows.Count > 0 Then
gridArtikels.PrimaryGrid.SetSelectedRows(0, 1, True)
ItemPanelImgs.Items.Clear()
'Dim images As New List(Of Article_Image)
Dim selectedNummer As String = String.Empty
selectedNummer = gridArtikels.PrimaryGrid.SelectedRows(0).Cells(1).Value.ToString()
'images = ArtikelsAndTheirVariationsFinal.GetImagesForArticle(selectedNummer)
'ItemPanelImgs.DataSource = images
End If
AddHandler gridArtikels.SelectionChanged, AddressOf gridArtikels_SelectionChanged
End Sub
P.S I am using to be concrete supergrid control from DotnetBar devcomponenets but it shouldn't be diffrent from ordinary controls behaviour.
What could be wrong here?
For those whom would like to debug here is sample app
EDIT:
I also tried this way but its still going to infinitive loop...
Public IgnoreSelectionChanged As Boolean = False
Private Sub gridArtikels_SelectionChanged(sender As Object, e As GridEventArgs) Handles gridArtikels.SelectionChanged
If IgnoreSelectionChanged Then Exit Sub
IgnoreSelectionChanged = True
If gridArtikels.PrimaryGrid.Rows.Count > 0 Then
gridArtikels.PrimaryGrid.SetSelectedRows(0, 1, True)
ItemPanelImgs.Items.Clear()
'Dim images As New List(Of Article_Image)
Dim selectedNummer As String = String.Empty
selectedNummer = gridArtikels.PrimaryGrid.SelectedRows(0).Cells(1).Value.ToString()
'images = ArtikelsAndTheirVariationsFinal.GetImagesForArticle(selectedNummer)
'ItemPanelImgs.DataSource = images
End If
IgnoreSelectionChanged = False
End Sub

How do I add then select the dynamic control I just added

I've got an application in VB.net which adds a picturebox to the selected mouse position within another picturebox control. I need to create a click event to select that new picturebox so I can drag it and drop it to a new location in the event that the first one was wrong or use a keypress event, those events I will code later, but I can not figure out how to select ANY of the dynamic controls.
In vb6 there was a way to select an index of the control, but there is no such animal in VB.net.
I've tried control groups, but for some reason I'm not getting results from them.
Here is the code I have so far
Private Sub PictureBox1_Click(sender As System.Object,
e As System.EventArgs) Handles PictureBox1.Click
Dim pb As New PictureBox
pb.BackColor = Color.Blue
Me.PictureBox1.Controls.Add(pb)
pb.Size = New Size(64, 110)
pb.Location = New Point(Cursor.Position.X - 64, Cursor.Position.Y - 110)
pb.Visible = True
End Sub
What in the name of all good things am I doing wrong here?
You need to write a generic event handler before time, using the sender parameter to refer to the object that raised the event.
Private Sub PictureBoxes_Click(sender As Object, e As EventArgs)
Dim pb = DirectCast(sender, PictureBox)
'Use pb here.
End Sub
When you create your control at run time, use an AddHandler statement to attach the method to the event.
Dim pb As New PictureBox
AddHandler pb.Click, AddressOf PictureBoxes_Click
That said, if you want to implement drag-n-drop then it's not the Click event you should be handling.
This little bit of code took some time, but I was able to do what I set out to so far...
This is before the Sub Main event
Public Class dynamicPB 'create a picturebox element which
'can be called anytime
Inherits PictureBox 'sets the type of control to a
'picturebox
Public Sub New() 'sets the function of the new box to
'default values
MyBase.BackColor = Color.AliceBlue
MyBase.BorderStyle = Windows.Forms.BorderStyle.Fixed3D
MyBase.Height = 50
MyBase.Width = 26
End Sub
End Class
in the actual main class
Private Sub <control_event> (blah...) Blah...
Dim intPosAdj_X As Integer = 13 'get an offset for the cursor
Dim intPosAdj_Y As Integer = 25
Dim newPictureBox As New dynamicPB 'sets the click of the mouse into a
'mode of drawing a new PB
With newPictureBox 'clean use of the code
AddHandler newPictureBox.Click, _
AddressOf PictureBox_Click 'establishes events for the mouse
'activity on the objects
AddHandler newPictureBox.MouseEnter, _
AddressOf PictureBox_MouseEnter
AddHandler newPictureBox.MouseLeave, _
AddressOf PictureBox_MouseLeave
pbName += 1 'gives a unique name to the
'picturebox in an "array" style
.Location = New System.Drawing.Point _
(xPos - intPosAdj_X, yPos - intPosAdj_Y) 'establish where the box goes
'and center the object on the
'mouse pointer
.Visible = True 'ensures that the box is visible
.Name = pbName 'names the new control
End With
Controls.Add(newPictureBox) 'add control to form
End Sub
Private Sub PictureBox_Click(sender As System.Object, e As System.EventArgs)
Dim dblMouseClick As Double = CType(DirectCast _
(e, System.Windows.Forms.MouseEventArgs).Button, MouseButtons) _
'make it simple to manipulate
'the event by putting the long
'code into a variable
If dblMouseClick = MouseButtons.Left Then
MsgBox("Left CLick")
ElseIf dblMouseClick = MouseButtons.Right Then
MsgBox("right click")
Else
MsgBox("Center")
End If
This actually resolves the issue of adding and being able to select the object
Thanks for all of the suggestions and help