2014-01-20 420 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 
    } 
}