C# webBrowser.Document.GetElementByTagName index - c#

the C# webBrowser form object allows me to access links within a page by their html Tag name.
By storing all of the links of a page in a collection
HtmlElementCollection links = webBrowser1.Document.GetElementsByTagName("a");
I can then cycle through them by their index and have the browser "click" on the link
links[i].InvokeMember("Click");
So, this index works with int, until this strange underhanded error pops, saying the value must be between 0 and -1 (-__-)
private void executeExtraction()
{
HtmlElementCollection links = webBrowser1.Document.GetElementsByTagName("a");
try
{
isDone = false;
Task find = Task.Factory.StartNew(() => links[i].InvokeMember("Click"));
}
catch (Exception e)
{
Debug.Print(e.ToString());
}
i++;
toolStripTextBox1.Text = i.ToString();
}
the "int i" is publicly declared outside this method
EDIT - Okay I found my problem...
it's a timer that is calling executeExtraction, so every tick, the HtmlElementCollection "links" gets created.
then a task takes links[i].InvokeMember("Click") on a new thread.
So, it had to do with the threading. the "links" list gets broken when it tries to access while an other thread is busy with it.
How do I solve this ?
thanks

Related

How to wait until selenium completes its navigation?

Ok here my code and but it immediately executes
private static ChromeDriver mainDriver;
mainDriver.Navigate().GoToUrl(srFetchUrl);
string srPageSource = mainDriver.PageSource;
I have to get the source code after the page is actually navigated to new page and page is loaded
You can try this method, this will wait until page loads completely and you can add your expected time to page load.
public void E_WaitForPageLoad() throws Exception
{
JavascriptExecutor js = (JavascriptExecutor)driver;
//This loop will rotate for 100 times to check If page Is ready after every 1 second.
//You can replace your if you wants to Increase or decrease wait time.
int waittime;
waittime = 60;
for (int i=0; i<waittime; i++)
{
try
{
Thread.sleep(1000);
}catch (InterruptedException e) {}
//To check page ready state.
if (js.executeScript("return document.readyState").toString().equals("complete"))
{
//System.out.println("Wait for Page Load : "+js.executeScript("return document.readyState").toString());
break;
}
}
System.out.println("\nWeb-Page Loaded.");
}
Thank You,
Ed D, India.
Specify , implicit or explicit wait till the element in the page is loaded.
refer this link for C# wait syntax

C# WebBrowser stuck on navigating when used in for loop

I have a for loop that changes the URL
for (int i = 1; i < max; i += 50)
{
completed = false;
string currkey = country;
crawler.Navigate(new Uri("http://www.example.net/func.php?dom=" + currkey + "&key=&start=" + i));
Console.WriteLine("Navigating to " + "http://www.example.net/func.php?dom=" + currkey + "&key=&start=" + i);
while (!completed)
{
Application.DoEvents();
Thread.Sleep(500);
}
}
This is my documentcompleted handler
crawler.Refresh();
Console.WriteLine("Getting universities");
getUniversities();
Console.WriteLine("Finished getting universities");
completed = true;
When i get rid of the for loop and use a single link, it seems to navigate to the website correctly, but when i use for loop to load websites in order, it seems that the web browser gets stuck in the second iteration.
Example:
currkey = United States
In the first iteration, the website link will be http://www.example.net/func.php?dom="United States"&key=&start=1, and on the next one it will be http://www.example.net/func.php?dom="United States"&key=&start=51. The navigation gets stuck when trying to load the second link.
I have used the boolean completed to note that the current iteration is finished, but it is still stuck.
Any kind of help is appreciated
Your Thread.Sleep call is blocking the WebBrowser from continuing to load. What you should be doing is attaching to the DocumentCompleted event, and then loading the next page. Please don't use this while/sleep combination in WinForms - you should use the events that the controls expose.
Attach the event:
crawler.DownloadCompleted += CrawlerDocumentCompleted;
Event handler:
private void CrawlerDocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
//The document has loaded - now do something
}
A final thought
As it looks like you are implementing a crawler, why are you using the WebBrowser control in WinForms to navigate. Surely all you are interested in is the html that the server serves up? Or is the page using JavaScript to load additional elements into the DOM, requiring you to use the WebBrowser?
You could use the WebClient class and the DownloadString or DownloadStringAsync methods. See https://msdn.microsoft.com/en-us/library/fhd1f0sw(v=vs.110).aspx

Firing WebBrowser.DocumentCompleted event whilst in a loop

I have a simple app I am developing that needs to iterate through a list of URLs which are passed to a WebBrowsers Navigate function in a for each loop. I was hoping to see the DocumentCompleted event firing after each call of the Navigate function but it only seems to be fired after the whole form has completed loading - and this the loop has completed.
I guess I am missing something fundamental here but some help and advice would be great!
Thanks!
Here is a sample of code that I am trying...
This foreach loop runs n the Form Load event of the WinForms page I am using...
int id = 0;
foreach (DataRow row in quals.Rows)
{
URN = row["LAIM_REF"].ToString();
string URN_formated = URN.Replace("/", "_");
string URL = "http://URL_I_AM_GOING_TOO/";
string FullURL = URL + URN_formated;
wbrBrowser.ScriptErrorsSuppressed = true;
wbrBrowser.Refresh();
wbrBrowser.Navigate(FullURL);
id += 1;
label1.Text = id.ToString();
}
At the point the loop gets to the line:
wbrBrowser.Navigate(FullURL);
I was hoping that the event:
private void wbrBrowser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
...
}
would fire therefore being able to run processes against each of the URLs returned in the loop.
Thanks!
I used:
while (wbrBackground.ReadyState != WebBrowserReadyState.Complete) { Application.DoEvents(); }
after the Navigate function and it now works as expected.

How to scroll a web page in Coded UI Test with VS 2012?

I'm recording Coded UI Tests with VS 2012, which shall test the functions of a web application.
After I loaded the web page, I click on a button to start p.e. a job application.
After the next page has loaded on the same site, my problem begins.
The entry controls are at the end of the web site.
To take a look and input data into the entry controls, I must scroll down.
The recording produced the following method in the UIMap.
Designer.cs:
public void Scrollen()
{
#region Variable Declarations
Playback.PlaybackSettings.WaitForReadyLevel = WaitForReadyLevel.AllThreads;
this.UIGoogleMozillaFirefoxWindow.UIItemPropertyPage.UIBewerbungDemoFirmaDocument.WaitForControlExist();
this.UIGoogleMozillaFirefoxWindow.UIItemPropertyPage.UIBewerbungDemoFirmaDocument.WaitForControlReady();
Playback.PlaybackSettings.WaitForReadyLevel = WaitForReadyLevel.UIThreadOnly;
WinControl uIBewerbungDemoFirmaDocument = this.UIGoogleMozillaFirefoxWindow.UIItemPropertyPage.UIBewerbungDemoFirmaDocument;
#endregion
// Click "Job application" document
Point pt = new Point(1390, 553);
int count = 0;
while (!uIBewerbungDemoFirmaDocument.TryGetClickablePoint(out pt) && count < 20)
{
count++;
System.Threading.Thread.Sleep(10);
if (count == 20)
Console.WriteLine("ClickablePoint not found");
}
Mouse.Click(uIBewerbungDemoFirmaDocument, new Point(1390, 553));
Mouse.MoveScrollWheel(10);
}
As You can see, I tried WaitForControlExist, WaitForControlReady, TryGetClickablePoint and the method MoveScrollWheel.
But neither Mouse.Click nor Mouse.MoveScrollWheel are working.
And in the next method, where I click into the first of the entry fields, I get a message at execution time, that the click event produces an error, because the control is hidden (because it's down below on the website, out of visible range).
After several tests this is making me crazy.
Any idea what has gone wrong and how can I scroll down the web site, so my entry controls are in visible range?
You can try Control.EnsureClickable(). Or you can use below mentioned function to scroll the page until the control is not clickable.
public static void ScrollAndClick(HtmlControl Control)
{
bool isClickable = false;
if (Control.TryFind())
{
while (!isClickable)
{
try
{
Control.EnsureClickable();
Mouse.Click(Control);
isClickable = true;
}
catch (FailedToPerformActionOnHiddenControlException)
{
Mouse.MoveScrollWheel(-1);
throw;
}
}
}
else
{
throw new AssertInconclusiveException("Control Not Found");
}
}
You can also add condition related to timeout to make sure it don't go to infinite loop.
Let me know if you are having issue with this at your end.

C# validate repeat last PostBack when hit Refresh (F5)

i have a webform that generates a file, but when i click the button that produces the postback to generate the file Once it finish if i press Refresh (F5) the page resubmit the postback and regenerates the file, there's any way to validate it and show a message to the user or simply DO NOTHING!
thanks :)
The simpler way will be to use Post Rediret Get pattern.
http://en.wikipedia.org/wiki/Post/Redirect/Get
Make sure to check out External Links on that Wikipedia article.
the browser should warn them if they hit refresh on a page that has been postbacked. how i handle it though is in the session track what i have done so i don't repeat certain actions. a simple flag should suffice.
Check for the existence of the file in question in your postback logic and only create the file if the file doesn't already exist:
if (false == System.IO.File.Exists(filename))
{
// create the file
}
else
{
// do whatever you do when the file already exists
}
i wrote a solution for this problem and here it is if anyone needs it.
protected void Page_Load(object sender, System.EventArgs e)
{
/*******/
//Validate if the user Refresh the webform.
//U will need::
//A global private variable called ""private bool isRefresh = false;""
//a global publica variable called ""public int refreshValue = 0;""
//a html control before </form> tag: ""<input type="hidden" name="ValidateRefresh" value="<%= refreshValue %>">""
int postRefreshValue = 0;
refreshValue = SII.Utils.convert.ToInt(Request.Form["ValidateRefresh"]); //u can use a int.parse()
if (refreshValue == 0)
Session["ValidateRefresh"] = 0;
postRefreshValue = SII.Utils.convert.ToInt(Session["ValidateRefresh"]); //can use a int.parse()
if (refreshValue < postRefreshValue)
isRefresh = true;
Session["ValidateRefresh"] = postRefreshValue + 1;
refreshValue = SII.Utils.convert.ToInt(Session["ValidateRefresh"]); //can use a int.parse()
/********/
if (!IsPostBack)
{
//your code
}
}
you just have to evaluate:
if (!isRefresh)
PostFile();
else
{
//Error msg you are refreshing
}

Categories