我想創建一個函數,從多個頁面獲取源代碼。在抓取每個頁面後,我想更新表單上的標籤以指示進度(5中的1個,5中的2個等)。任務凍結GUI
但是,無論我嘗試什麼,GUI完全凍結,直到for
循環結束。
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;
}
這個方法的調用看起來是這樣的:
List<List<string>> pages = site.GetPages(url, num_pages);
如果我刪除task.Wait();
的GUI解凍,標籤更新正常,但代碼繼續,而不需要的多維列表。
我應該說我對C#很陌生。我做錯了什麼?
更新
按照達林,我已經改變了我的方法:
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;
}
和呼叫:
List<List<string>> pages = await site.GetPages(url, num_pages);
不過,現在我得到這個錯誤:
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'.
但是,當我用async標記方法時,GUI仍然凍結。
更新2
Woops!我似乎錯過了達林的一種新方法。我現在在該方法中包含await webGet.LoadAsync(url + i);
。我還標記了我從async
撥打的方法。
現在,不幸的是,我得到這個錯誤:
'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?)
我檢查,我使用.NET 4.5.2,在我引用HtmlAgilityPack是Net45的版本。我不知道現在發生了什麼事。
有一個更新UI的單個線程。如果你用'task.Wait()'阻止該線程,那麼UI不能更新。 – Enigmativity
你錯過了達林方法中最重要的部分:「等待webGet.LoadAsync(url + i)'。僅僅因爲一個方法被標記爲'async'並不會自動使它異步。如果您不等待任何事情,它將同步運行並凍結UI。 – sstan
WinForms。我應該使用WPF嗎? – zuddsy