1

I want to wait until browser.ReadyState == WebBrowserReadyState.Complete. There's DocumentCompleted Webbrowser's event, but if the page is being loaded by using AJAX it does fire when the HTML is ready, the missing contentes being loaded by ajax isn't available at this time. My first ide was:

int[] myFunction() {

  int[] values;

 while (browser.ReadyState != WebBrowserReadyState.Complete) {
         Application.DoEvents();
  }
             values = get_values_from_browser();
  return values;
}

it doesn't works return soon than it should and I get wrong value in the array, for example, all the elements are the same. However, if I use a Timer it does Works (I get correct values in the array) but I can't return from the function because I don't know when return from function.

The timer is:

System.Windows.Forms.Timer timer1 = new System.Windows.Forms.Timer();
     int[] myFunction() {

      int[] values;
      timer1.Interval = 1000;
                timer1.Tick += new EventHandler(delegate(object o, EventArgs ea)
                    {
                            if (browser.ReadyState == WebBrowserReadyState.Complete)
                            {
                                timer1.Stop();
                                values = get_values_from_browser();
                            }
                    });
                timer1.Start();
          return values;
    }

So my question is: Why it does works using a new thread (the System.Windows.Forms.Timer) but doesn't with the while loop in the main thread? any Thread.Sleep(x) in the main case will make it work.

Jack
  • 16,276
  • 55
  • 159
  • 284
  • If the first piece of code runs from the UI thread, you are probably blocking the browser from doing any work since you occupy the thread and never let any other computing happen on it. – Moti Azu Nov 13 '14 at 16:33
  • Actually, I'm not. I'm using `Application.DoEvents();` forget to type it here – Jack Nov 13 '14 at 16:35
  • I can't say I know for sure why it's not working, so this is not an answer to your question. But the second implementation with the timer is the better way to go even if the first solution would work. You can even decrease the timer interval and get a responsive UI as opposed to the first solution. – Moti Azu Nov 13 '14 at 16:39
  • @MotiAzu: The problem with the second solution is: after `timer1` is stopped and the function to extract data from webBrowser is called, I'd like to return to function. But how could I do that? – Jack Nov 13 '14 at 17:03
  • You can use a callback delegate, here's an example https://gist.github.com/motiazu/e614a48b577f45001102 – Moti Azu Nov 13 '14 at 17:09
  • Which web browser control are you using? – John Saunders Nov 13 '14 at 17:14
  • @MotiAzu: It seems to be a nice solution. But it implies in some changes the "design" of my program: rather than hold all the return value from `get_values_from_browser()` into an array and then process them I should process them on-the-fly instead of.... – Jack Nov 13 '14 at 17:20
  • @JohnSaunders: This one: http://msdn.microsoft.com/en-us/library/system.windows.forms.webbrowser(v=vs.110).aspx – Jack Nov 13 '14 at 17:32
  • I added the [tag:winforms] and [tag:webbrowser-control] tags to your question, so that's clearer. – John Saunders Nov 13 '14 at 17:38
  • @JohnSaunders: Thanks. I edited title too – Jack Nov 13 '14 at 18:53

2 Answers2

1

An AJAX page is non-deterministic. E.g., its JavaScript logic might be using its own timers to make XHR requests, in which case browser.ReadyState wouldn't be a reliable indicator of any pending activity. Moreover, I'm not even sure XHR request themselves count towards browser.ReadyState. WebBrowser.IsBusy is more likely to account for that. On a side note, don't use Application.DoEvents(), in most cases it's a pure evil.

To solve the problem, you could use asynchronous polling. I've answered a similar question with some sample code here:

https://stackoverflow.com/a/20934538/1768303.

Community
  • 1
  • 1
noseratio
  • 59,932
  • 34
  • 208
  • 486
  • 1
    I don't know why but I wasn't notified about your answer on this topic. That's why I just tried it now. Thank you SO much, man. It worked *exactly* as I wanted. I've working on it for several days trying a lot of differents approachs and Reading about thread to try get some help. Have a nice day. – Jack Nov 17 '14 at 02:10
  • I could give you 50+ if I can but that question doesn't have bounty. – Jack Nov 17 '14 at 02:12
  • @Jack, no worries, glad it helped. I have some other related answers, e.g. http://stackoverflow.com/questions/22239357/how-to-cancel-task-await-after-a-timeout-period/22262976#22262976 – noseratio Nov 17 '14 at 02:14
  • 1
    It has been 3th time you saved my life when using WebBrowser. You have so much skills man. I favorited that topic. Thank you! – Jack Nov 17 '14 at 02:18
0

In your first method you're doing:

int[] myFunction() {

   int[] values;

   while (browser.ReadyState != WebBrowserReadyState.Complete) {
        values = get_values_from_browser();
        Application.DoEvents();
   }

   return values;
}

shouldn't this be:

int[] myFunction() {

   int[] values;

   while (browser.ReadyState != WebBrowserReadyState.Complete) {
       Application.DoEvents();
   }

   values = get_values_from_browser();
   return values;

}

John Earnshaw
  • 331
  • 3
  • 14
  • yes, it is. I type that code here the SO's textarea and forget it. But it doesn't Works anyway – Jack Nov 13 '14 at 18:54