is there a better way to do this - vb.net

so i have a loop in vb.net that loads a webpage, fills out a form and clicks submit
I currently am using these for, respectively, waiting for the webpage to load, filling out the form, and clicking submit
Do While Not browser.ReadyState = WebBrowserReadyState.Complete
System.Windows.Forms.Application.DoEvents()
Loop
and
browser.Document.GetElementById("text").SetAttribute("value", message)
and
For Each element As HtmlElement In browser.Document.GetElementsByTagName("input")
If element.GetAttribute("type") = "submit" Then
element.InvokeMember("click")
End If
Next
but my problem is that after around the fifth time the loop is run it srrors on the line with the set attribute. And i have a feeling that it is not waiting for the webpage to load before it tries filling out the form, and that is why it is erroring.
Does anyone know a better way to do this?

You can use DocumentCompleted Event, this event ensures your document is ready, and all required sections loaded
Private Sub browser_DocumentCompleted(ByVal sender As System.Object, ByVal e As System.Windows.Forms.WebBrowserDocumentCompletedEventArgs) Handles browser.DocumentCompleted
' YOUR FORM FILLING CODE HERE
End Sub
and for form submit you can use, forms' submit() method like this
browser.Document.GetElementById("text").DOMElement.form.submit()

Maybe the element "text" isn't loaded yet or isn't on the page?
You could make some javascript to do that task, and inject it into the page.
Here is how to make a "click" in javascript:
https://developer.mozilla.org/en/DOM/document.createEvent

Related

More info on click event in VB

I would like to create a bot that repeats the same action many times. Is there any way I can get more info about a click event. Lets say I click somewhere on the opened file explorer window. Can the program tell that I clicked on a specific area or button in that window? Can I make the program click or type on a specific(opened) window?
Thanks
Yes the program can tell when you click on a specific button. Whatever button it is that you clicked on will have its click event fired, if it exists. In order to manually tell the program to perform this action, you can implement the phrase..
btn.PerformClick()
where "btn" is the name of whatever button you are needing to click. Whenever this phrase is called, the btn_Click event handler will be fired just the same as if you yourself actually clicked the button.
To do the same thing with an actual window or form in your program is trickier because there are no built in methods you can call to trigger a windows form click event. But it is possible. The code that will define a window's event handler and trigger it will be..
Private Sub myWindow_Click() Handles MyBase.Click
'code you want to run on click event here
End Sub
myWindow_Click() 'where you want the click to be triggered
The above would be much simpler to simulate in a method call however.
And lastly to simulate the typing of text into a window, you could simply access the text property of the control you are wanting to alter, and then change that text property to the desired text. But judging from your question, you are wanting this to be done in a similar fashion to how a human would.
This can also be accomplished with some work, using a timer interval that appends to the text of the control.
Lets say for example, you wanted "hello world" to be typed into a text box on screen as a person would. Add a timer control to your form and set its interval to 250 or however fast you want the word to be type and in a method..
Dim str as String = ""
Dim pos as Integer = 0
Public Sub humanType(word as String)
str = word
Timer1.enabled = true
End Sub
public Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
myTextBox.Text = myTextBox.Text + str[pos]
pos = pos + 1
If pos = str.length Then
Timer1.enabled = false
End If
End Sub
If you have never worked with timer intervals before, this tutorial has some good info on them for VB.Net. http://www.techrepublic.com/article/perform-actions-at-set-intervals-with-vbnets-timer-control/
Hope it helps!

VB.net (2010) Click-through on all controls

I'm having a application with quite a few tabpages. One function of my program is that if the user leaves the application for more than 3 minutes, I display the main tabpage where the most relevant information is shown (this is done by a timer called "back_to_main_tab"). So far so good. However in a few tabpages you can enter text and "take a pause" for more than these 3 minutes, and if that happens, the user is taken back to the main tab, without his/her consent, erasing his/her entered text.
I realize that this could be solved by enabling/disabling the back_to_main_tab-timer at strategic places, but I would like to solve it by resetting the timer each time a click is registered in the application regardless of what is is clicked. The reason for this is that the problem isn't unique for a certain tabpage, so I would like to have a "all-purpose"-fix for all tabpages.
Is this possible?
Thanks in advance
Jonas
You can write an Event Handler for each element where user can write.
For example
Private Sub TextBox1_KeyDown(ByVal sender As System.Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles TextBox1.KeyDown
'Reset timer
End Sub
(and you could try KeyUp or KeyPress too).
So you can reset timer each time the user write something somewhere.
Btw if the 3mins pass (after last KeyPress), the back_to_main_tab erase all.
EDIT
Ok so you could make one function to Manage the CLICK event. And attach the function to all items form.
To attacch an event handler to alla element you could try something like this
Private Sub AddGenericEventHandler()
For Each Ctrl As Item In Form.Items
AddHandler Ctrl.Click, AddressOf MyClickHandler
Next
End Sub
And write the function that reset your timer
Public Sub MyClickHandler(ByVal sender As System.Object, ByVal e As System.EventArgs)
'Timer Reset
End Sub
This is an Idea. You have to write correctly the FOR EACH to catch all form items do you need.

DataGridViewLinkColumn formatting

My Application is a windows form application in VB.
I have DataGridView in my Application. The seventh column is defined as DataGridViewLinkColumn when i designed the DataGridView. My Application reads the link from a table and Grid properly displays it.
I don't want my user to see the link, i want them to see a sentence like "Click here to visit" but i couldn't manage to do.
Second, when i click the link nothing happens. I know that i have to handle this in CellContentClick event but i don't know how to call the default browser directed to the link.
Thanks in advance.
There is no direct property in DataGridViewLinkColumn which separates the display text and url.
To achieve your goal, you need to handle two events CellFormatting and CellContentClick. Subscribe to these events.
In CellFormatting event handler, change the formatted value to Click here to visit. The flag FormattingApplied must be set True as this prevents further formatting of the value.
Private Sub dataGridView1_CellFormatting(sender As Object, e As DataGridViewCellFormattingEventArgs)
If e.ColumnIndex = 'link column index Then
e.Value = "Click here to visit";
e.FormattingApplied = True;
End If
End Sub
To open the link in the default browser, use the Process class and pass the url as argument to the Start method. Put the code in the CellContentClick event handler.
Private Sub dataGridView1_CellContentClick(sender As Object, e As DataGridViewCellEventArgs)
If e.ColumnIndex = 'link column index Then
Process.Start(dataGridView1(e.ColumnIndex, e.RowIndex).Value.ToString());
End If
End Sub

All Controls Click event on form

Is there a simple way to Activate the form when any controls in the form is clicked like datagirdview, panel, menustrip, button, textbox, label, etc....
it happens that my project can show many different form and it's hard for me to activate one form when it's on the back of the active form. I need to clicked the border of the form to activate it.
most likely your problem arises because your form is MDI child.. you'll have to click the menu bar to activate the form.. but if you have a borderless form, clicking on controls wont activate the form.. again, this usually happens on MDI but it shouldnt happen on a regular winform.. unless you have other running events in the background that interferes with the process.
You question is not clear at all, and I don't know what you are trying to archieve, but for executing something with a click event you have to add the handler for every control.
If you are declaring it not dinamically just:
Private Sub ControlsClick(sender As Object, e As EventArgs) _
Handles Panel1.Click, Button1.Click, TextBox2.Click ' etc.
Me.Activate 'Or Whatever
End Sub
You have to add the handler for each control. The same if you do it dinamically:
Private Sub InitializeClickHandlers(sender As Control, Optional bChilds As Boolean = True)
For Each elem As Control In sender.Controls
AddHandler elem.Click, AddressOf ControlsClick(elem, New EventArgs)
If bChilds AndAlso elem.Controls.Count > 0 Then
Call InitializeClickHandlers(sender)
End If
Next
End Sub
Then, for every control in the form, you call it like: Call InitializeClickHandlers(Me)
Or, for every control inside a panel: Call InitializeClickHandlers(Panel1)

vb.net webbrowser documentcompleted event - page not loading

I have searched the other questions surrounding the WebBrowser DocumentCompleted event, but no-one seems to have the exact problem that I am having.
I am trying to automate searching flights on an airline website. The first url I use is the same every time except for the date part so it's easy enough to get the WebBrowser to go the URL by combining strings. However, that page is a disclaimer page that has a 'proceed' button that needs to be clicked before prices are shown. If I use a series of buttons on a form, I can get to the first URL by clicking button1, and then click the proceed button by clicking button2. It works fine.
However, I wanted to remove the need to click button2 so attempted to use the WebBrowser DocumentCompleted event. The problem that I am having is that the first page never seems to fully load in the webbrowser and so the button is never clicked.
This is the code that I am using for the two buttons and the DocumentCompleted event
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
TextBox1.Text = fullURL
WebBrowser1.Navigate(fullURL)
End Sub
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
Dim allElements As HtmlElementCollection = WebBrowser1.Document.All
For Each webpageelement As HtmlElement In allElements
If webpageelement.GetAttribute("src") = proceedbuttonattribute Then
webpageelement.InvokeMember("click")
End If
Next
End Sub
Private Sub WebBrowser1_DocumentCompleted(ByVal sender As System.Object, ByVal e As System.Windows.Forms.WebBrowserDocumentCompletedEventArgs) Handles WebBrowser1.DocumentCompleted
If TextBox1.Text.StartsWith(firstURL) = True Then 'make sure that button is only clicked after first webpage loads
Dim allElements As HtmlElementCollection = WebBrowser1.Document.All
'Click 'Proceed to Booking' button
For Each webpageelement As HtmlElement In allElements
If webpageelement.GetAttribute("src") = proceedbuttonattribute Then
webpageelement.InvokeMember("click")
End If
Next
End If
End Sub
Thanks!
WebBrowser1.Navigate(fullURL)
Do While wb.ReadyState <> WebBrowserReadyState.Complete
Application.DoEvents()
Loop
;)
When you say DocumentCompleted is never triggered, do you mean it isn't triggered at all or are you saying that maybe the If statement isn't returning True, and therefore the contents (and click action) are not run?
Also, are there any frames or iframes on this page? Because, if there are, DocumentCompleted will not run until each and every single frame is loaded and completed, and if its an ajaxed frame, then that will introduce mroe problems. All it takes is for one of the frames to not load properly or remain in "Interactive" mode (where .readystate = 3) instead of it being fully and properly loaded (where .readystate = 4) and this will prevent the DocumentCompleted event from getting triggered.
Also, how long are you waiting for the DC event to trigger?
There is a better way around this, all you need to do is run a Do/While loop, with the exact same code as in your DC event, and it will just sit there (after the .Navigate2 is called) and just wait until that button shows up in the DOM, and as soon as the following returns True, you can use .InvokeMember and click on the button.
If webpageelement.GetAttribute("src") = proceedbuttonattribute Then
So, in this case, you will create another function named "WaitUntilButtonFound" and perhaps place a 100 millisecond Sleep (wait) between each loop, and a .DoEvents (found in .Threading namespace) right after or before the Sleep method (also found in .Threading I think).
This way, as soon as the button of relevance appears in the Document Object Model, you can click it, and if you want, as soon as its found, you can wait another 2 - 3 seconds (if you want, no real need) and then click it. Because finding that button in the DOM is an indicator that the page has either loaded, or partially loaded (where the relevant or necessary part has completed loading), so that you can resume the action you wanted to take on that button (which is, to click it), right after it appears. In fact, it'll be the quickest way to move forward as well.
What do you think? Let me know how you go and if you need more help or guidance. Also, if you could let us know if the DC event is absolutely not being triggered or if it's just your IF statement that is blocking the DC from running the code inside the DC event, that would be helpful, because if the DC event is being triggered but code inside isn't running because of the If statements inside it, that is something entirely different to the DC even not being triggered at all.
Let us know, thanks.