2014-01-20 419 views
0

我正在開發一個插入到Windows窗體應用的插件,用於在地圖上顯示終端的位置(在WebBrowser控件中)。情況如下:等待異步HTTP請求的響應,無異步/等待

  1. 用戶單擊按鈕(調用插件);
  2. 異步HTTP請求被創建(確定終端的座標);
  3. 由於全部收到響應 - 地圖應顯示給用戶。

我寫的代碼:

foreach (var terminal in terminals) 
{ 

    var webRequest = (HttpWebRequest)WebRequest.Create(GeoCoder.GeoCodeUrl + terminal.Address); 
    var taskResp = Task.Factory.FromAsync<WebResponse>(webRequest.BeginGetResponse, 
                 webRequest.EndGetResponse, 
                 terminal.Id); 
    var taskResult = taskResp.ContinueWith(task => 
    { 
     // Parse the response 
    }); 
    runningTasks.Add(taskResult); 
} 
Task.WaitAll(runningTasks.ToArray()); // UI Thread blocks here! 
webBrowser1.DocumentText = ... 

它會阻止UI線程,因爲我不得不等待,直到我得到所有響應(座標)之前,我可以顯示地圖。我想知道如何避免這種情況(沒有發出同步http請求)?

P.S.我知道如何使用異步/等待,但不能使用它們 - 我必須使用.NET 4.0和VS2010 - Microsoft.Bcl.Async不能幫助)。

回答

1

就我所見,你對它感到震驚如何在c#4.0中做到這一點。

它並不難,保持用來做這些類型的工作在NET 1.0也頭腦的人,甚至在此之前:)

var uiTaskScheduler = TaskScheduler.FromCurrentSynchronizationContext(); 
Task.Factory.ContinueWhenAll(runningTasks.ToArray(), antecedents => 
{ 
    webBrowser1.DocumentText = ...//This runs in UI thread 
},CancellationToken.None, TaskContinuationOptions.None,uiTaskScheduler); 

我缺少的東西?

0

你可以使用System.Threading.ThreadPool.QueueUserWorkItem來啓動你的代碼,它將在一個單獨的線程上運行它到UI但記住你需要調用webBrowser1.DocumentText = ...,因爲如果你不會的話你會得到一個異常。 希望這有助於。

+0

我需要調用'webBrowser1.DocumentText = ...',只要我得到**最後一個響應**。我不明白如何使用'ThreadPool.QueueUserWorkItem'來完成它,請給我更多的細節? – Zharro

0

BackgroundWorker類提供了一種輕鬆簡單的方法來遠離UI線程執行工作。在.DoWork事件處理程序中執行您的工作,並在完成後調用UI線程以執行.RunWorkerComplete事件處理程序,您可以在其中使用地圖更新UI。

class Form1 
{ 
    private System.ComponentModel.BackgroundWorker bgw; 

    public Form1() 
    { 
    bgw = new BackgroundWorker(); 
    bgw.DoWork += WorkMethod; 
    bgw.RunWorkerCompleted += WorkCompleteMethod; 
    } 

    private void Button1_Click(object sender, eventargs e) 
    { 
    if (!bgw.IsBusy) 
    { 
     bgw.RunWorkerAsync(); 
    } 
    } 

    private void WorkMethod(object sender, DoWorkEventArgs e) 
    { 
    //perform work 
    //set result to e.Result 
    } 

    private void WorkCompleteMethod(object sender, RunWorkerCompletedEventArgs e) 
    { 
    //extract result from eventargs 
    //update ui 
    } 
}