1

I want my function to wait until the event WebBrowser.DocumentCompleted is completed.

I am using AutoResetEvent and here is my code:

private static WebBrowser _browser = new WebBrowser();
private static AutoResetEvent _ar = new AutoResetEvent(false);

private bool _returnValue = false;

public Actions() //constructor
{
        _browser.DocumentCompleted += PageLoaded;
}

public bool MyFunction()
{
    _browser.Navigate("https://www.somesite.org/");
    _ar.WaitOne(); // wait until receiving the signal, _ar.Set()
    return _returnValue;
}

private void PageLoaded(object sender, WebBrowserDocumentCompletedEventArgs e)
{
    // do not enter more than once for each page
    if (e.Url.AbsolutePath != (sender as WebBrowser).Url.AbsolutePath)
        return;

    _returnValue = true;

    _ar.Set(); // send signal, unblock my function
}

Here my problem is, PageLoaded never gets fired, and my function gets stuck on _ar.WaitOne();. How can I fix this issue ? perhaps there is another way to achieve this ?

0014
  • 893
  • 4
  • 13
  • 40
  • Are you sure DocumentCompleted event is subscribed? Also did you try loading different websites? – Nemo Feb 15 '16 at 04:16
  • @Nemo yes I am. The event gets fired if I remove `_ar.WaitOne();` – 0014 Feb 15 '16 at 04:41
  • 1
    This doesn't work because you block the message the message pump of the UI thread. Using a loop with `DoEvents` to solve this might be temptive but is also plain wrong. You can use `async/await` to approach this, [example](http://stackoverflow.com/a/20934538/1768303). – noseratio Feb 15 '16 at 21:50
  • @noseratio Thanks for the idea. Later on I'll view the example and try to apply it. However, since its your own answer, im sure you would be capable answering this non-complicated answer without spending much time on it. Please answer it if you can. – 0014 Feb 16 '16 at 02:56
  • I did answer it in the comments and suggested a right way of doing it. If you still want a `WaitOne` which pumps messages, [here](http://stackoverflow.com/a/21573637/1768303) you go. The side-effects can be quite nasty, especially if this application has visual UI a user can interact with. – noseratio Feb 16 '16 at 03:08
  • @Noseratio Your code works perfectly, I really appreciate your input. However, since my code is synchronous I am not able to use `async/await`. If I need to use your solution as a module, I still have to find a way to wait for results from async functions right ? – 0014 Feb 18 '16 at 14:06
  • If you should not be synchronously waiting on the main UI thread, period. If however this is a web scrapping scenario, you can do something like this: http://stackoverflow.com/a/19718530/1768303. – noseratio Feb 18 '16 at 21:49
  • With a UI app, at least you could use a modal dialog to organize the wait: http://stackoverflow.com/a/20891625/1768303 – noseratio Feb 18 '16 at 21:54
  • @Noseratio Yes this (stackoverflow.com/a/19718530/1768303) is exactly what I am after. However I think there is something wrong with the code. It gets stuck on `task.Wait();` I tried to make it work and I failed. I also saw the posted answer where you got the idea, but I didn't have a chance to look at it. I'll try to derive my answer from that post if you wont have time to fix your own code. Thanks for your suggestion though all of them are very helpful ! – 0014 Feb 20 '16 at 02:47

1 Answers1

0

Here is how you can synchronously get the page data of a website. This will help me build my web automation API. Special thanks to @Noseratio he helped me finding this perfect answer.

private static string _pageData = "";

public static void MyFunction(string url)
{
    var th = new Thread(() =>
    {
        var br = new WebBrowser();
        br.DocumentCompleted += PageLoaded;
        br.Navigate(url);
        Application.Run();
    });
    th.SetApartmentState(ApartmentState.STA);
    th.Start();
    while (th.IsAlive)
    {
    }

    MessageBox.Show(_pageData);
}

static void PageLoaded(object sender, WebBrowserDocumentCompletedEventArgs e)
{
    var br = sender as WebBrowser;
    if (br.Url == e.Url)
    {
         _pageData = br.DocumentText;
        Application.ExitThread();   // Stops the thread
     }
    }
}
0014
  • 893
  • 4
  • 13
  • 40