I am trying to make create a function to get the source code from a number of pages. After each page is grabbed, I want to update a label on my form indicating the progress (1 of 5, 2 of 5, etc.).
However, no matter what I try, the GUI completely freezes until the for
loop has ended.
public List<List<string>> GetPages(string base_url, int num_pages)
{
var pages = new List<List<string>>();
var webGet = new HtmlWeb();
var task = Task.Factory.StartNew(() => {
for (int i = 0; i <= num_pages; i++)
{
UpdateMessage("Fetching page " + i + " of " + num_pages + ".");
var page = new List<string>();
var page_source = webGet.Load(url+i);
// (...)
page.Add(url+i);
page.Add(source);
pages.Add(page);
}
});
task.Wait();
return pages;
}
The call to this method looks like this:
List<List<string>> pages = site.GetPages(url, num_pages);
If I remove task.Wait();
the GUI unfreezes, the label updates properly, but the code continues without the needed multidimensional list.
I should say that I'm very new to C#. What the heck am I doing wrong?
Update
As per Darin, I have changed my method:
public async Task<List<List<string>>> GetPages(string url, int num_pages)
{
var pages = new List<List<string>>();
var webGet = new HtmlWeb();
for (int i = 0; i <= num_pages; i++)
{
UpdateMessage("Fetching page " + i + " of " + num_pages + ".");
var page = new List<string>();
var page_source = webGet.Load(url+i);
// (...)
page.Add(url+i);
page.Add(source);
pages.Add(page);
}
return pages;
}
And the call:
List<List<string>> pages = await site.GetPages(url, num_pages);
However, now I am getting this error:
The 'await' operator can only be used within an async method. Consider marking this method with the 'async' modifier and changing its return type to 'Task'.
But when I mark the method with async, the GUI still freezes.
Update 2
Woops! I seem to missed a piece of Darin's new method. I have now included await webGet.LoadAsync(url + i);
in the method. I have also marked the method I am calling from as async
.
Now, unfortunately, I'm getting this error:
'HtmlWeb' does not contain a definition for 'LoadAsync' and no extension method 'LoadAsync' accepting a first argument of type 'HtmlWeb' could be found (are you missing a using directive or an assembly reference?)
I've checked, I'm using .NET 4.5.2, and the HtmlAgilityPack in my References is the Net45 version. I have no idea what's going on now.
Assuming WinForms, start by making the toplevel eventhandler async void
.
You then have an async method that can await
a Task<List<List<string>>>
method. That method does not have to be async
itself.
private async void Button1_Click(...)
{
var pages = await GetPages(...);
// update the UI here
}
public Task<List<List<string>>> GetPages(string url, int num_pages)
{
...
return task;
}