简体   繁体   中英

How to synchronously access webbrowser.navigate

How to get the html after navigating from webbrowser like as below in the code. This a dll library that can be used in other projects and it is not a winforms. After calling navigate it does not wait.

public List<Category> Categories;
public WebBrowser Browser;

public List<Category> ListAllCategories()
{
    Browser.DocumentCompleted += ReadAllCategories;
    Browser.Navigate(CoursesLink);
    //want to wait here until categories are built in the ReadAllCategories method without wasting CPU cycles
    return Categories;
}

void ReadAllCategories(object sender, WebBrowserDocumentCompletedEventArgs e)
{
    WebBrowser browser = sender as WebBrowser;
    switch (browser.ReadyState)
    {
        case WebBrowserReadyState.Complete:
            if (browser.Document != null)
            {
                //buildingListofCategories
            }
            break;
        case WebBrowserReadyState.Interactive:
            break;
        case WebBrowserReadyState.Loaded:
            break;
        case WebBrowserReadyState.Loading:
            break;
        case WebBrowserReadyState.Uninitialized:
            break;
        default:
            break;
    }
    browser.DocumentCompleted -= ReadAllCategories;
}

There's a couple ways to support this. One way is to simply encapsulate the asynchronous operation in one method using synchronization primitives to block the thread until the operation is completed asynchronously ( Warning: not tested ):

public List<Category> GetAllCategories(Uri CoursesLink)
{
    List<Category> categories = new List<Category>();
    ManualResetEventSlim waitEvent;
    using (WebBrowser browser = new WebBrowser())
    {
        waitEvent = new ManualResetEventSlim();
        browser.DocumentCompleted += (s, e) =>
        {
            switch (browser.ReadyState)
            {
                case WebBrowserReadyState.Complete:
                    // TODO: your processing, filling categories
                    waitEvent.Set();
                    break;
                // TODO: error processing
            }
        };
        browser.Navigate(CoursesLink);
    }
    waitEvent.Wait(); // TODO: timeout?
    return categories;
}

The other, of course, is to use the built-in Task support in .NET to model the inherently asynchronous task in a Task object (similar to what Schabse mentioned) and simply call Wait ( Warning: not tested ):

public Task<List<Category>> GetAllCategoriesAsync(Uri CoursesLink)
{
    var tcs = new TaskCompletionSource<List<Category>>();
    List<Category> categories = new List<Category>();
    using (WebBrowser browser = new WebBrowser())
    {
        browser.DocumentCompleted += (s, e) =>
        {
            switch (browser.ReadyState)
            {
                case WebBrowserReadyState.Complete:
                    // TODO: your processing, filling categories
                    tcs.SetResult(categories);
                    break;
                    // TODO: error processing
            }
        };
        browser.Navigate(CoursesLink);
    }
    return tcs.Task;
}

//...

public List<Category> ListAllCategories()
{
    return GetAllCategoriesAsync(CoursesLink).Result;
}

I would recommend using the Task -based method as it better models the fact that what you have is an asynchronous operation and that you're actually waiting for it to complete. In addition, you could then use it asynchronously in a UI:

var categories = await GetAllCategoriesAsync(CoursesLink);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM