vb.net Detect if a link is clicked in Webbrowser control - vb.net

I have a Webbrowser control on a standard windows form in VB.NET 2005. I just want to detect when someone clicks a link inside the Webbrowser control it just tells me what they clicked on, or where its trying to go, then cancel the process.
I tried putting..
MsgBox(e.Url)
e.Cancel = True
Inside of the WebBrowser1_Navigating EVENT, but that does nothing. Can anyone help?

This was the problem:
MsgBox(e.Url)
Try this:
MsgBox(e.Url.ToString())
Private Sub WebBrowser1_Navigating(ByVal sender As Object, ByVal e As System.Windows.Forms.WebBrowserNavigatingEventArgs) Handles WebBrowser1.Navigating
If MsgBox("You are trying to go to:" & vbCr & e.Url.ToString() & vbCr & "Cancel Navigate?", MsgBoxStyle.YesNo) = MsgBoxResult.Yes Then
e.Cancel = True
End If
End Sub

you could try something like adding a handler for each link:
For Each htmlEle As HtmlElement In Webbrowser1.document.Links
addhandler htmlElec.click, addressof YourSub
Next
private sub YourSub()
'do what you want here
end sub

Related

Have to Click Form To Give Focus

I have a main form with buttons that open a custom message box form. It works fine if it's just a message and the user just needs to click OK. But if the answer to that message box is important, like "Are you sure you want to delete this file?" I use a while loop to wait for the user to respond and once they do then a flag is set from false to true and the response is recorded.
For some reason any response that uses a while loop to wait is causing the message box form to not have focus after being called. Requiring the user to first click on the form, and then click on OK.
So far I've tried using form.Activate() instead of form.Show(), as well as calling Application.DoEvents() inside the while loop since I believed the while loop was taking focus away from the message form immediately after being called. Neither solved the issue.
Code from a message box that works as intended:
If cmbLoadProgram.SelectedItem = "" Then
frmMessageBox.lblHeader.Text = "Set-Up"
frmMessageBox.lblMessageText.Text = "No Program Selected!"
frmMessageBox.Show()
Exit Sub
End If
Code from a message box that needs to be clicked twice:
If btnGetHexStart.Visible = False And cmbStartCondition.SelectedItem = "Pixel" Then
frmMessageBox.lblHeader.Text = "Hex Set-Up"
frmMessageBox.lblMessageText.Text = "Reset Hex Code Data?"
frmMessageBox.Show()
Me.Hide()
While Flag = False
If frmMain.OKCancel = "OK" Then
btnGetHexStart.Visible = True
btnGetHexStart.Enabled = True
btnGetHexStart.PerformClick()
Flag = True
End If
frmMain.delay(20)
End While
End If
I'm wanting both options to only need to be clicked once in order to confirm or cancel the action. Instead of the while loop questions needing to be clicked twice.
This just an idea from me, just how to open msgboxform, here we need MessageForm and one module1, for example:
Public Class MessageForm
'You can assign any variable to show any data in messageform display
Private Sub btnOK_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnOK.Click
theResult = MsgBoxResult.Ok
Me.Close()
Me.Dispose()
End Sub
Private Sub bttcancel_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles bttcancel.Click
theResult = MsgBoxResult.Cancel
Me.Close()
Me.Dispose()
End Sub
End Class
Module Module1
Public theResult As MsgBoxResult
'You can add some parameter here to submit to MessageForm
Public Function myMessageBox() As MsgBoxResult
myMessageBox = MsgBoxResult.Cancel
MessageForm.ShowDialog()
myMessageBox = theResult
End Function
End Module
and then you can call the myMessageBox anywhere like this:
'if myMessageBox procedure have parameter, apply the paramters too
dim myRslt = myMessageBox()
You don't need to create a form,You can use DialogResult and MessageBox.Show, code:
Dim Result As DialogResult = MessageBox.Show("Set-Up" & vbCrLf & "No Program Selected!", "Warning", MessageBoxButtons.OKCancel)
If Result = DialogResult.OK Then
ElseIf Result = DialogResult.Cancel Then
End If

reread content of webbrowser window/wait for user input

In my program I want to give 2 input-fields within a webbrowser-window a value and then wait for the user to click a login button. After this, I want the program to break out of the loop when the screen contents "Welcome!" (which it contains after logging in).
But now the problem: When the values for username and password are set, the do-loop starts instantly. So even if I click the login-button, the loop still contains the content of the webpage before the button was clicked and it will loop forever.
How can I solve this? I thought about two ways so far:
Reread the html code after button clicked so the "Welcome!" will be inside the code and then the loop will break, or
Wait for the user to press the login-button.
But in both ways I have no real idea how to solve it.
WebBrowserWindow.WebBrowser1.Navigate("[...]")
Do
If WebBrowserWindow.WebBrowser1.ReadyState = WebBrowserReadyState.Complete Then
If WebBrowserWindow.WebBrowser1.Document.Body.InnerHtml.ToString.Contains("Login") Then Exit Do
End If
Application.DoEvents()
Loop
If WebBrowserWindow.WebBrowser1.Document.Body.InnerHtml.ToString.Contains("Login") Then
WebBrowserWindow.WebBrowser1.Document.Window.Frames(2).Document.GetElementById("username").SetAttribute("value", sUser)
WebBrowserWindow.WebBrowser1.Document.Window.Frames(2).Document.GetElementById("password").SetAttribute("value", sPass)
Application.DoEvents()
Dim DocumentCompletedHandler As WebBrowserDocumentCompletedEventHandler = Sub(dcsender As Object, dcargs As WebBrowserDocumentCompletedEventArgs)
If WebBrowserWindow.WebBrowser1.ReadyState = WebBrowserReadyState.Complete Then
RemoveHandler WebBrowserWindow.WebBrowser1.DocumentCompleted, DocumentCompletedHandler
'Put the code that should be executed when the user has logged in here.
MsgBox("it works")
End If
End Sub
AddHandler WebBrowserWindow.WebBrowser1.DocumentCompleted, DocumentCompletedHandler
End If
WebBrowserWindow.Close()
Me.Close()
I noticed the problem when I tried to put the html code in a message box. It just contained the 'old' code.
Thanks in advance
The golden rule of WinForms is: NEVER, EVER use Application.DoEvents() to keep your UI responsive! If you need to use it then you are almost always doing something wrong (see: Keeping your UI Responsive and the Dangers of Application.DoEvents).
Heavy operations should never be done on the UI thread, but in a background thread. There are multiple ways of taking the work of the UI, for instance Tasks, Threads or using the BackgroundWorker.
HOWEVER in this case, you don't even need a loop. The WebBrowser has got a DocumentCompleted event that is raised every time a page (or an iframe inside the page) has loaded completely. Use that to know when to execute your code.
Having that said, here's how you'd migrate it to DocumentCompleted:
WebBrowserWindow.WebBrowser1.Document.Window.Frames(2).Document.GetElementById("username").SetAttribute("value", sUser)
WebBrowserWindow.WebBrowser1.Document.Window.Frames(2).Document.GetElementById("password").SetAttribute("value", sPass)
Dim DocumentCompletedHandler As WebBrowserDocumentCompletedEventHandler = _
Sub(dcsender As Object, dcargs As WebBrowserDocumentCompletedEventArgs)
If WebBrowserWindow.WebBrowser1.ReadyState = WebBrowserReadyState.Complete Then
RemoveHandler WebBrowserWindow.WebBrowser1.DocumentCompleted, DocumentCompletedHandler
'Put the code that should be executed when the user has logged in here.
End If
End Sub
AddHandler WebBrowserWindow.WebBrowser1.DocumentCompleted, DocumentCompletedHandler
'Any code put here won't wait for the user to log in, it wil be executed pretty much immediately.
Here's a little test project: http://www.mydoomsite.com/sourcecodes/WebBrowser_WaitForUserInteraction.zip
Ultimately, your entire code can be changed to:
WebBrowserWindow.WebBrowser1.Navigate("[...]")
Dim FirstDocumentCompletedHandler As WebBrowserDocumentCompletedEventHandler = _
Sub()
'Check if:
' - The web browser has finished loading.
' - WebBrowser1.Document is not Null.
' - WebBrowser1.Document.Body is not Null.
' - WebBrowser1.Document.Body.InnerHtml is not Null.
' - WebBrowser1.Document.Body.InnerHtml contains "Login".
If WebBrowserWindow.WebBrowser1.ReadyState = WebBrowserReadyState.Complete AndAlso _
WebBrowserWindow.WebBrowser1.Document IsNot Nothing AndAlso _
WebBrowserWindow.WebBrowser1.Document.Body IsNot Nothing AndAlso _
WebBrowserWindow.WebBrowser1.Document.Body.InnerHtml IsNot Nothing AndAlso _
WebBrowserWindow.WebBrowser1.Document.Body.InnerHtml.Contains("Login") Then
'The code put in here will execute when the page loads the first time, and the above conditions are met.
'We are at the login page. Enter the credentials.
WebBrowserWindow.WebBrowser1.Document.Window.Frames(2).Document.GetElementById("username").SetAttribute("value", sUser)
WebBrowserWindow.WebBrowser1.Document.Window.Frames(2).Document.GetElementById("password").SetAttribute("value", sPass)
Dim SecondDocumentCompletedHandler As WebBrowserDocumentCompletedEventHandler = _
Sub(dcsender As Object, dcargs As WebBrowserDocumentCompletedEventArgs)
If WebBrowserWindow.WebBrowser1.ReadyState = WebBrowserReadyState.Complete Then
RemoveHandler WebBrowserWindow.WebBrowser1.DocumentCompleted, SecondDocumentCompletedHandler
'The code put in here will be executed after the user has pressed "Login".
MsgBox("it works")
WebBrowserWindow.Close()
Me.Close()
End If
End Sub
AddHandler WebBrowserWindow.WebBrowser1.DocumentCompleted, SecondDocumentCompletedHandler 'Add the second DocumentCompleted event handler.
RemoveHandler WebBrowserWindow.WebBrowser1.DocumentCompleted, FirstDocumentCompletedHandler 'Remove the first DocumentCompleted event handler.
End If
End Sub
AddHandler WebBrowserWindow.WebBrowser1.DocumentCompleted, FirstDocumentCompletedHandler
'Again, any code put here will execute almost immediately, thus NOT waiting for the page to load.
Alternatively
...if you think it's too messy having lambdas everywhere, you can fall back to using regular methods:
Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
WebBrowserWindow.WebBrowser1.Navigate("[...]")
AddHandler WebBrowserWindow.WebBrowser1.DocumentCompleted, AddressOf WebBrowserWindow_FirstDocumentCompleted
End Sub
Private Sub WebBrowserWindow_FirstDocumentCompleted(sender As System.Object, e As System.Windows.Forms.WebBrowserDocumentCompletedEventArgs)
'Check if:
' - The web browser has finished loading.
' - WebBrowser1.Document is not Null.
' - WebBrowser1.Document.Body is not Null.
' - WebBrowser1.Document.Body.InnerHtml is not Null.
' - WebBrowser1.Document.Body.InnerHtml contains "Login".
If WebBrowserWindow.WebBrowser1.ReadyState = WebBrowserReadyState.Complete AndAlso _
WebBrowserWindow.WebBrowser1.Document IsNot Nothing AndAlso _
WebBrowserWindow.WebBrowser1.Document.Body IsNot Nothing AndAlso _
WebBrowserWindow.WebBrowser1.Document.Body.InnerHtml IsNot Nothing AndAlso _
WebBrowserWindow.WebBrowser1.Document.Body.InnerHtml.Contains("Login") Then
'We are at the login page. Enter the credentials.
WebBrowserWindow.WebBrowser1.Document.Window.Frames(2).Document.GetElementById("username").SetAttribute("value", sUser)
WebBrowserWindow.WebBrowser1.Document.Window.Frames(2).Document.GetElementById("password").SetAttribute("value", sPass)
AddHandler WebBrowserWindow.WebBrowser1.DocumentCompleted, AddressOf WebBrowserWindow_SecondDocumentCompleted 'Add the second DocumentCompleted event handler.
RemoveHandler WebBrowserWindow.WebBrowser1.DocumentCompleted, AddressOf WebBrowserWindow_FirstDocumentCompleted 'Remove the first DocumentCompleted event handler.
End If
End Sub
Private Sub WebBrowserWindow_SecondDocumentCompleted(sender As System.Object, e As System.Windows.Forms.WebBrowserDocumentCompletedEventArgs)
If WebBrowserWindow.WebBrowser1.ReadyState = WebBrowserReadyState.Complete Then
RemoveHandler WebBrowserWindow.WebBrowser1.DocumentCompleted, AddressOf WebBrowserWindow_SecondDocumentCompleted
'Put the code that should be executed when the user has logged in here.
MsgBox("it works")
WebBrowserWindow.Close()
Me.Close()
End If
End Sub

VB.NET - Code after Me.Close is executed

Update: Solution by #Mark Hall:
Using Exit Sub after the Me.Close to prevent further execution of the sub while the Closing event is going on..
I'm trying to open up a popup window on closing a form where the user can decide if he really wants to close the form.
Therefore I wrote:
Private Sub Form1_FormClosing_1(ByVal sender As System.Object, ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles MyBase.FormClosing
e.Cancel = True 'Fenster wird nicht geschlossen
Dim DialogExit As DialogResult
DialogExit = MsgBox("Do you want to exit the setup process?", vbQuestion Or MsgBoxStyle.OkCancel, "Exit Setup?")
Select Case DialogExit
Case Windows.Forms.DialogResult.OK
Me._Result_ThisForm = Result_Form.Yes
e.Cancel = False
Case Else
'Just no exit
End Select
End Sub
But when I call Me.Close from somewhere in the code, the form just doesn't close but it executes further code!
Like in (somewhere in the code):
If bErr = False Then
Me._Result_ThisForm = Result_Form.Goto_Next ' Just an additional info Enum
Me.Close()
End If
MsgBox("This should not pop up if bErr = false")
-> The "Exit Setup?" MsgBox pops up correctly but the user presses "ok" to exit the programm, the MessageBox from after the "Me.Close()" suddenly appers an then the program closes.
What causes this behavior?
Thank you for your help!

MsgBox YesNo solution needed

I have done the following in a LoginForm:
Private Sub OK_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles OK.Click
If UsernameTextBox.Text = ("username") And PasswordTextBox.Text = ("password") Then MainMenu.Show(Me.Hide) Else MsgBox("Wrong")
End Sub
But it gives me the following error:
Error 1 Expression does not produce a value (on Me.Hide)
If the LoginForm is the "startup" for the application, note that other forms will become children of this form. You'll be able to close the application one with Application.Exit() which is really not a good practice. You should close the application by closing the "startup" form.
With that said, Ranhiru is correct.
MainMenu.Show 'Show the MainMenu form
Me.Hide 'Hide the LoginForm
Are you trying to hide the Main Menu and Hide the current form ?
If so, try
If UsernameTextBox.Text = ("username") And PasswordTextBox.Text = ("password") Then  
MainMenu.Show
Me.Hide
Else
MsgBox("Wrong")

Help with events

I have multiple textboxes which I want them to perform the same thing upon clicking them. By default I can use the handles textbox1.click for 1 single textbox as shown below but I am not sure how to do handle multiples of them. Of course I can write a handler for every single textbox but I have about 50 of them. I am sure there must be a more efficient way. Please advice. Thanks.
Sub TextBox1_click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles TextBox1.Click
If Button9.Text = "Make Changes" Then
If TextBox2.Text <> "" Then
Frm_Cine1.Show()
Frm_Cine1.chooseCine(ComboBox1.SelectedItem)
Else
MsgBox("Please check input!")
Exit Sub
End If
End If
End Sub
why don't you create a customizable textbox?
If Button9.Text = "Make Changes" Then
If TextBox2.Text <> "" Then
These two lines are going to be same for all those 50 buttons?
If yes, then I think you can assign same event handler to each of the button's click event.
Other way is, create one private method which takes one string as an argument and returns boolean value depending on whether your string is blank or not and call this method from all the 50 button's click event.
Thanks for all your advices, I am not sure if this is what you guys are suggesting but apparently it is how I wanted it to work:
Sub TextBoxs_click(ByVal sender As System.Object, ByVal e As System.EventArgs) _
Handles TextBox2.Click, TextBox3.Click, TextBox4.Click 'This part is disturbing if I have 50 textboxes...
'For Each obj As Control In Panel2.Controls
If sender.GetType.ToString = "System.Windows.Forms.TextBox" Then
Dim txtbox As TextBox = sender
textbox_verification(txtbox)
End If
'Next
End Sub
Sub textbox_verification(ByVal txtbox As TextBox)
If Button9.Text = "Make Changes" Then
If txtbox.Text <> "" Then
Frm_Cine1.Show()
Frm_Cine1.chooseCine(ComboBox1.SelectedItem, "FILE1-->This should be a variable")
Else
MsgBox("Please check timings input!")
Exit Sub
End If
End If
End Sub
If you indeed need to use the same click handler for multiple test boxes, you can use the AddHandler command to associate the click event of each test box with the handler routine, as shown:
AddHandler TextBoxX.Click AddressOf TextBox1_Click
You will need to add this statement to your program (maybe in the form load routine) once for each text box you want to handle. (Using the name of each text box in place of the "TextBoxX" in the above code.)