WebClient - 等到文件下载完毕

时间:2012-03-15 20:47:59

标签: c# silverlight windows-phone-7

我正在开发一个函数来返回一个从xml文件生成的集合。

最初,我使用本地xml文件进行测试,但现在我已准备好让应用程序从服务器下载真正的xml文件。由于WebClient对象需要被赋予OpenReadCompleted事件处理程序这一事实,我很难看到我如何能够做到这一点 - 我无法从此处返回集合数据,并且此时也是如此处理程序执行后,原始函数已经结束。

我的原始代码如下:

public static ObservableCollection<OutletViewModel> GetNear(GeoCoordinate location)
{
    ObservableCollection<OutletViewModel> Items = new ObservableCollection<OutletViewModel>();

    // Load a local XML doc to simulate server response for location
    XDocument xDoc = XDocument.Load("SampleRemoteServer/outlet_list.xml");

    foreach (XElement outlet in xDoc.Descendants("outlet"))
    {
        Items.Add(new OutletViewModel()
        {
            Name = outlet.Attribute("name").Value,
            Cuisine = outlet.Attribute("cuisine").Value
        });
    }

    return Items;
}

如何在此函数中加载文件,运行事件处理程序,然后继续该函数?

唯一可以想到的是添加一个循环来继续检查变量,这个变量由事件处理程序代码更新......这听起来不是一个好的解决方案。

谢谢, 约什

2 个答案:

答案 0 :(得分:2)

您将foreach()循环移动到已完成的事件。

这确实意味着你无法从原始方法中返回任何内容。设为void

这是异步I / O的工作原理,最好习惯它。您需要重新考虑您的设计。

答案 1 :(得分:1)

您应该开始看一下异步编程。 一种(旧学校)方式是实现公共事件并在调用类中订阅该事件。

然而,使用回调更优雅。我掀起了一个你可以构建的简单(无用,但仍然是概念上有效)的例子:

public static void Main(string[] args)
{
  List<string> list = new List<string>();

  GetData(data =>
  {
    foreach (var item in data)
    {
      list.Add(item);
      Console.WriteLine(item);
    }
    Console.WriteLine("Done");
  });
  Console.ReadLine();
}

public static void GetData(Action<IEnumerable<string>> callback)
{
  WebClient webClient = new WebClient();
  webClient.DownloadStringCompleted += (s, e) =>
    {
      List<string> data = new List<string>();
      for (int i = 0; i < 5; i++)
      {
        data.Add(e.Result);
      }
      callback(e.Error == null ? data : Enumerable.Empty<string>());
    };

  webClient.DownloadStringAsync(new Uri("http://www.google.com"));
}

如果您想加入C# async行列(link for WP7 implementation),可以使用新的asyncawait关键字实现该目标:

public static async void DoSomeThing()
{
  List<string> list = new List<string>();
  list = await GetDataAsync();

  foreach (var item in list)
  {
    Console.WriteLine(item);
  }
}

public static async Task<List<string>> GetDataAsync()
{
  WebClient webClient = new WebClient();
  string result = await webClient.DownloadStringTaskAsync(new Uri("http://www.google.com"));

  List<string> data = new List<string>();
  for (int i = 0; i < 5; i++)
  {
    data.Add(result);
  }
  return data;
}