WebBrowser control - wait for page loading after submit form - c#

I am new to c# and its concepts, so i am sorry if this question is kind of dumb.
I try to do some automatation using the winforms webbrowser control
elements = webBrowser1.Document.GetElementsByTagName("input");
foreach (HtmlElement element in elements)
{
if (element.GetAttribute("value") == "Anzeigen")
element.InvokeMember("click");
}
while (webBrowser1.ReadyState != WebBrowserReadyState.Complete) Application.DoEvents();
// do some math on recived html
// ......
// show results
MessageBox.Show(numPlanets.ToString() );
So, to explain it:
Im looking for a Button with the value "Anzeigen", simulate a click on it, then wait till NEW page is loaded and do my calculations then.
Unfortunately my calculations are done on the OLD HTML content, because its not waiting for the page to load. Strangely if i enter an Thread.Sleep(5000); after the foreach loop, this Sleep is executed BEFORE the click is simulated, and the calculation fails also.
I just need some synchronous behavior for that click, withouth using an event.
Hope u can help me with that, sorry for my bad english
EDIT:
Solved it like this:
Variable bool webbbrowserfinished = false inside the class, if i want synchronous behavior, i do it like this:
webbrowserfinished = false;
// do navigation here
while (!webbrowserfinished)
{
Application.DoEvents();
Thread.Sleep(100);
}
webbrowserfinished = false;

You can try WebBrowser.DocumentCompleted Event
Occurs when the WebBrowser control finishes loading a document.
private void Form1_Load(object sender, EventArgs e)
{
webBrowser1.Navigate("google.com");
webBrowser1.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(webBrowser1_DocumentCompleted);
}
void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
MessageBox.Show("Completed Now!");
}

Well it isn't the best of solutions but you could always start a timer when the web browser navigates, and set timer1.Tick to something like 3000, then within the timer1_Tick method you can do your calculations on the new page, and then timer1.Stop();.
There is probably a better solution using events but I'm not too good with web browsers myself.

You can use Thread.sleep(5000) to wait for your page to load, because if you don't, the navigate method will load a new doc into web browser control but it will not call document_complete_event_handler

Related

Endless loop with InvokeMember c#

I'm trying to mark some checkboxes and then submit a form using webbrowser, I succeeded, the problem is that my program is getting endless, It appears the form submitted, and then my form before being submitted, again submitted and again before being submitted and again...again....again.... infinitely so. I do not understand why.
I have realized that it happens in this part:
form.InvokeMember ("submit");
This is my code
private void Form1_Load(object sender, EventArgs e)
{
webBrowser1.Navigate("https://www.mysite.com");
}
private void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
this.Text = e.Url.ToString() + " loaded";
webBrowser1.Document.GetElementById("check1").InvokeMember("CLICK");
webBrowser1.Document.GetElementById("check2").InvokeMember("CLICK");
webBrowser1.Document.GetElementById("check3").InvokeMember("CLICK");
webBrowser1.Document.GetElementById("check4").InvokeMember("CLICK");
webBrowser1.Document.GetElementById("check5").InvokeMember("CLICK");
foreach (HtmlElement form in webBrowser1.Document.Forms)
{
if (form.Name == "SearchForm")
{
form.InvokeMember("submit");
}
}
}
private void webBrowser1_Navigating(object sender, WebBrowserNavigatingEventArgs e)
{
this.Text = "Navigating";
}
Well you've said that any time you finish loading a page, you want to submit the search form. So when that submit finishes, it will finish loading the page... and you'll trigger the same event. It's an entirely natural loop.
You should ask yourself what condition you want to detect that means you should submit the form when the page has finished loading. Should it only be when there isn't already something in the search box, for example? Or make it change based on the URL? Or perhaps you simply want to unhook the event handler for "document completed" before you submit the form? We can't really tell without more context, but that's why you're setting that behaviour.
Victor, try having a different form (*.aspx) for the submit action.

Get source of Webpage in Webbrowser C#

Currently I have a website loaded in a WebBrowser component, which keeps changing stuff inside a certain <a> inside the page. In order for me to get the data, I have to create another WebRequest each 5 seconds, just to refresh the data (I think they're called dynamic pages). I've tried fetching the data from the WebBrowser (WebBrowser.DocumentText), but the value just remained the same, even though I am pretty sure it changed, because I can see it changed. I think the webrequest each 5 seconds takes up unnecesary memory space, and that this can be done easier.
Do you guys maybe know a way for me to do this?
Guessing at Winforms. You'll want to use the Document property to read back the DOM. Here's an example. Start a new Winforms project and drop a WebBrowser on the form. Then a label and a timer. Make the code look like this:
public partial class Form1 : Form {
public Form1() {
InitializeComponent();
webBrowser1.Url = new Uri("http://stackoverflow.com/questions/10781011/get-source-of-webpage-in-webbrowser-c-sharp");
webBrowser1.DocumentCompleted += webBrowser1_DocumentCompleted;
timer1.Interval = 100;
timer1.Tick += new EventHandler(timer1_Tick);
}
void timer1_Tick(object sender, EventArgs e) {
var elem = webBrowser1.Document.GetElementById("wmd-input");
label1.Text = elem.InnerText;
}
void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e) {
timer1.Enabled = true;
}
}
The browser will navigate to your question. Type something in the Answer box, note how the label displays what you typed.
You'll need to tweak this code to work with your specific web page, alter the "wmd-input" element name. Use a DOM inspection tool to find the name. I like Firebug.
You could try to get the source via JavaScript.
Use the InvokeScript method to execute return document.documentElement.outerHTML;
This will return an Object which you should be able to type cast to a String.

System.Threading.Timer example to run and display seconds until you click a button

I am having some issues creating an asp.net page using C#
When you first click a button it starts the display of seconds via a label control.
When you click the button again the seconds stop.
Currently my code does just prints 0 and stops:
System.Threading.Timer Timer;
bool endProcess = false;
int i = 0;
protected void Page_Load(object sender, EventArgs e)
{
Timer = new System.Threading.Timer(TimerCallback, null, 10, 10);
Label1.Text = i.ToString();
i++;
}
private void TimerCallback(object state)
{
if (endProcess == true)
{
Timer.Dispose();
return;
}
}
public void Button1_Click(object sender, System.EventArgs e)
{
endProcess = true;
}
You must set the label.text=i.toString(); in timecallback function not in page_load
For this to work in ASP.NET, you should not use System.Threading.Timer, because this runs on the server side and you need to have the client side updated periodically. You have afew options for a WEB based application.
Keep in mind that you do not push UI updates to a web browser, the web browser needs to pull or request the update. So, a naive solution would be to have the browser periodically do a postback to the web server to get the updated text for the label. Not a good solution, but I share this as the basic premise of the concept.
I think the best option would be to this entirely on the client side using a javascript timer and updating the DOM element with the new value. Take a look at the second and third example on this page
http://www.w3schools.com/js/js_timing.asp

How to know that WebBrowser control has finished loading all content including flash?

is there a way to know that the WebBrowser control has finished loading the page?
currently i am using WebBrowser.ReadyState == WebBrowserReadyState.Complete.
but this indicates that the webpage content is downloaded but sometimes the flash is not loaded yet.
A Flash file loading doesn't report its progress on that back to the browser so unfortunately you can't catch that.
well the best thing i have found is to use a timer to wait for a specifique time like 30 seconds and then the page should be loaded.
not perfect but the best i have thought of.
If you have control over the Flash, you can put an ActionScript event that will then get passed to the browser.
The WebBrowser control has a DocumentCompleted event which you can catch and react on. I don't know if that includes the Flash content loading - the docs aren't very clear on that....
webBrowser1.DocumentCompleted +=
new WebBrowserDocumentCompletedEventHandler(webBrowser1_DocumentCompleted);
private void webBrowser1_DocumentCompleted(object sender,
WebBrowserDocumentCompletedEventArgs e)
{
// do whatever you need to do when the document is completely loaded here
}
You can try this way:
bool loadingPage = true;
private void Browser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
if (this.ReadyState != WebBrowserReadyState.Complete) return;
if ((e.Url.AbsolutePath == "blank") || (e.Url != this.Url)) return;
if (this.Document.Body.All.Count < 20) return;
loadingPage = false
}
private void WaitPageLoad()
{
//To avoid waiting forever. You can add timer here.
while(loadingPage)
{
}
}

How to stop a event from firing + ASP.NET

I have a WebPage on which I have to detect and prevent usage of Browser Refresh Button. (Now Please, dont suggest me Response.Redirect, I wont be able to use it in this scenario).
On looking at this page http://aspalliance.com/687_Preventing_Duplicate_Record_Insertion_on_Page_Refresh.4 I found the way. I'm planning to put this idea in a Control and place the control on every page.
Now that my page contains so many buttons and other controls. My concern is, If it is a refresh post... I dont want any events to get fired...
It will be tedious to go and check whether it is a refresh post in the beginning of every event as my entire application is almost built.
Any ideas that would help me.
Raja
Including the below text for sake of more clarity :
Hi All, I hope a little misunderstanding... I dont want to stop user pressing the Refresh button... But all I want is to adjust my application's response accordingly... Imagine a scenario, when user clicks BUTTON-A a popup window opens with another page. Now when the user comes back and clicks refresh button in the main window, the click event of BUTTON-A is fired again and popup window is opened again... In such scenario, I want to refresh the page as such, without opening the popup window. so, I need to stop ASP.NET from firing the click event of BUTTON-A (or any other similar buttons)
I know you're not going to want to hear this but users expect to be able to hit the refresh button. Breaking something they like will make them unhappy. They'll blame you and your name will be mud.
Just think about those sites that try to block the Back button: do you like them?
This is at least a starting point on how you can do it. I'm not sure all logic is 100%, but it is something to begin with...
protected void Page_Load(object sender, EventArgs e)
{
foreach (Control control in Controls)
{
DisableEvent(control);
}
}
protected void Page_PreRender(object sender, EventArgs e)
{
foreach (Control control in Controls)
{
UpdateViewstate(control);
}
}
private void DisableEvent(Control current)
{
foreach (Control control in current.Controls)
{
if (control.GetType() == typeof(Button))
{
if (IsPostBack)
{
if (Session["update" + control.ID].ToString() != ViewState["update" + control.ID].ToString())
{
RemoveClickEvent((Button)control);
}
else
{
((Button)control).Click += new EventHandler(Button_Disable);
}
}
else
{
Session["update" + control.ID] = Server.UrlEncode(System.DateTime.Now.ToString());
}
}
DisableEvent(control);
}
}
private void UpdateViewstate(Control current)
{
foreach (Control control in current.Controls)
{
if (control.GetType() == typeof(Button))
{
ViewState["update" + control.ID] = Session["update" + control.ID];
}
UpdateViewstate(control);
}
}
void RemoveClickEvent(Button b) {
System.Reflection.FieldInfo f1 = typeof(Button).GetField("EventClick", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic);
object obj = f1.GetValue(b);
System.Reflection.PropertyInfo pi = typeof(Button).GetProperty("Events", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
System.ComponentModel.EventHandlerList list = (System.ComponentModel.EventHandlerList)pi.GetValue(b, null);
list.RemoveHandler(obj, list[obj]);
}
protected void Button_Disable(object sender, EventArgs e)
{
Button b = (Button)sender;
Session["update" + b.ID] = Server.UrlEncode(System.DateTime.Now.ToString());
}
You cannot prevent the user from pressing the Refresh button. It's build in functionality in the browser that resends the previous request, get or post. It's just there.
That is why that you normally make a redirect after a post to a get (e.g. the user posts to user/1/edit and the response redirects to user/1/view), so that a refresh will not cause double post.
I'm sorry that this is not what you want to hear, but when making a web application, you should try to follow web standards and let the user be able to use those browser features that he/she expects: back, forward, and refresh. And I know that your application is almost finished.
But if you start creating hacks for preventing refresh, or other stuff where you're not flowing with the technology, but going up against the stream, your application will start carrying around a bad package, and as the application lives on and is extended, this bad package is going to be a burden for further development.

Categories

Resources