2

I have a wpf program where i want to add a WebBrowser control

I search how to check if the WebBrowser loaded the page successfully or not and here is the code:

private async Task PageLoad(int TimeOut)
{
    TaskCompletionSource<bool> PageLoaded = null;
    PageLoaded = new TaskCompletionSource<bool>();
    int TimeElapsed = 0;
    webBrowser.LoadCompleted += (s, e) =>
    {
        if (webBrowser.ReadyState != webBrowser.Complete) return;
        if (webBrowser.Task.IsCompleted) return;
        PageLoaded.SetResult(true);
    };

    while (PageLoaded.Task.Status != TaskStatus.RanToCompletion)
    {
        //interval of 10 ms worked good for me
        await Task.Delay(10);
        TimeElapsed++;
        if (TimeElapsed >= TimeOut * 100)
        {
            //This prevents your method or thread from waiting forever
            PageLoaded.TrySetResult(true);
        }
    }
}

But why it doesn't work on wpf. How do I convert it?

I check it and the ReadyState Complete and Task.IsCompleted don't have a property like that in wpf. What is the code for wpf?

Massimiliano Kraus
  • 3,638
  • 5
  • 27
  • 47
imadammy
  • 83
  • 1
  • 5
  • Possible duplicate of [Async/Await implementation of WebBrowser class for .NET](http://stackoverflow.com/questions/8610197/async-await-implementation-of-webbrowser-class-for-net) – Massimiliano Kraus Dec 03 '16 at 00:54
  • Checking with the webpage is loaded is a dubious thing. The web browser control and IE both let you hook into document.complete events. But of course the problem is that many javascript frameworks also start loading things only after the document has finished loading. So you can have a document.complete event fire, but there could still be script running that is dynamically adding more the webpage. – Alexander Ryan Baggett Dec 12 '16 at 23:44

3 Answers3

3

You could just handle the LoadCompleted event of the WebBrowser control. This event will be raised when the web page being navigated to has finished downloading: https://msdn.microsoft.com/en-us/library/system.windows.controls.webbrowser.loadcompleted(v=vs.110).aspx

The WebBrowser control doesn't provide any asynchronous API or Task property that you can await. It simply raises an event so handling this event is the best thing you can do really:

webBrowser.LoadCompleted += (s, e) =>
{
    //the page has been loaded here. Do your thing...
};

If you only want to wait "TimeOut" number of seconds for the page to get loaded you could for example use a SemaphoreSlim that you release in the LoadCompleted event handler:

    private async Task LoadPageAsync(string url, int timeOutInSeconds)
    {
        using (System.Threading.SemaphoreSlim semaphore = new System.Threading.SemaphoreSlim(0, 1))
        {
            bool loaded = false;
            webBrowser.LoadCompleted += (s, e) =>
            {
                semaphore.Release();
                loaded = true;
            };
            webBrowser.Navigate(url);

            await semaphore.WaitAsync(TimeSpan.FromSeconds(timeOutInSeconds));

            if (loaded)
            {
                //page was loaded
            }
            else
            {
                //page was not loaded...
            }
        }
    }
mm8
  • 163,881
  • 10
  • 57
  • 88
0

I've been trying almost every solution suggested. Here's the one that solved my problem. Call this method before you try to interact with the page:

public void CheckWebBrowser()
{
       while (wb.IsBusy || wb.ReadyState != WebBrowserReadyState.Complete )
            {
                Application.DoEvents();
            }
        return;
}

I hope it helps!

0

This thread is old, but just in case someone else needs to solve this same problem here is what worked for me.

private async Task ButtonClickHandler(object sender, RoutedEventArgs args)
    {
        var urlList = new List<string>
        {
            "https://www.google.com/",
            "https://www.facebook.com/",
            "https://www.youtube.com/"
        };

        await LoopUrlsAsync(urlList);
    }

    private async Task LoopUrlsAsync(List<string> urlList)
    {
        TaskCompletionSource<bool> tcsNavigation = null;
        TaskCompletionSource<bool> tcsDocument = null;

        //These event bindings can be separated out to other methods, but for simplicity I've left them here. 
        WebBrowser.Navigated += (s, e) =>
        {
            tcsNavigation.SetResult(true);
        };

        WebBrowser.LoadCompleted += (s, e) =>
        {
            //Put logic here for what you want to happen when the document is finished loading
            tcsDocument.SetResult(true);
        };

        foreach (var url in urlList)
        {
            tcsNavigation = new TaskCompletionSource<bool>();
            tcsDocument = new TaskCompletionSource<bool>();

            WebBrowser.Navigate(url);

            await tcsNavigation.Task;
            await tcsDocument.Task;
        }
    }
dball
  • 374
  • 2
  • 10