从Windows Phone应用程序中的DownloadStringCompleted处理程序填充并返回实体

时间:2013-01-12 06:41:36

标签: c# windows-phone-7

我有一个从url获取HTML的方法,通过解析它来提取实体,并返回entites列表。这是示例代码:

  public List<Entity> FetchEntities()
    {
        List<Entity> myList = new List<Entity>();
        string url = "<myUrl>";
        string response = String.Empty;
        client = new WebClient();
        client.DownloadStringCompleted += (sender, e) =>
        {
            response = e.Result;
            // parse response
            // extract content and generate entities
            // <---- I am currently filling list here
        };
        client.DownloadStringAsync(new Uri(url));

        return myList;
    }

问题是当异步调用正在进行时,控制返回空myList。我怎么能阻止这个。我的最终目标是返回已填写列表。

此方法也在一个单独的类库项目中,并从windows phone应用程序调用,我必须保持它只是这样。有没有办法做到这一点,或者我错过了什么?任何帮助将不胜感激。

2 个答案:

答案 0 :(得分:4)

这就是异步编程非阻塞的重点。您可以将回调作为参数传递,并在其他地方处理结果,而不是尝试返回它。

如果您需要返回结果,可以使用this TPL library,我已经暂时使用它了一段时间。

public Task<string> GetWebResultAsync(string url)
     {
         var tcs = new TaskCompletionSource<string>();
         var client = new WebClient();

         DownloadStringCompletedEventHandler h = null;
         h = (sender, args) =>
                 {
                     if (args.Cancelled)
                     {
                         tcs.SetCanceled();
                     }
                     else if (args.Error != null)
                     {
                         tcs.SetException(args.Error);
                     }
                     else
                     {
                         tcs.SetResult(args.Result);
                     }

                     client.DownloadStringCompleted -= h;
                 };

         client.DownloadStringCompleted += h;
         client.DownloadStringAsync(new Uri(url));

         return tcs.Task;
     }
}

调用它正是你在.net 4.0中使用TPL的原因

GetWebResultAsnyc(url).ContinueWith((t) => 
                                    {
                                         t.Result //this is the downloaded string
                                    });

或:

var downloadTask = GetWebResultAsync(url);
downloadTask.Wait();
var result = downloadTask.Result; //this is the downloaded string

希望这会有所帮助:)

答案 1 :(得分:4)

你可以将回调传递给这样的方法,并在没有任务的情况下使其成为异步,所以你必须稍微更新方法用法。

public void FetchEntities(
    Action<List<Entity>> resultCallback, 
    Action<string> errorCallback)
{
    List<Entity> myList = new List<Entity>();
    string url = "<myUrl>";
    string response = String.Empty;
    client = new WebClient();
    client.DownloadStringCompleted += (sender, e) =>
    {
        response = e.Result;
        // parse response
        // extract content and generate entities
        // <---- I am currently filling list here

        if (response == null)
        {
            if (errorCallback != null)
                errorCallback("Ooops, something bad happened");
        }
        else
        {
            if (callback != null)
                callback(myList);
        }
    };
    client.DownloadStringAsync(new Uri(url));
}

另一种选择是强制它是同步的。像那样

public List<Entity> FetchEntities()
{
    List<Entity> myList = new List<Entity>();
    string url = "<myUrl>";
    string response = String.Empty;
    client = new WebClient();
    AutoResetEvent waitHandle = new AutoResetEvent(false);
    client.DownloadStringCompleted += (sender, e) =>
    {
        response = e.Result;
        // parse response
        // extract content and generate entities
        // <---- I am currently filling list here

        waitHandle.Set();
    };
    client.DownloadStringAsync(new Uri(url));

    waitHandle.WaitOne();

    return myList;
}