非阻止下载

时间:2011-11-06 19:10:45

标签: c# windows-phone-7 webclient

我是Windows Phone 7开发的新手,如果愿意,我在查找如何在“后台”中下载某些数据时会遇到一些麻烦。我知道这是可能的,因为像ESPN等应用程序显示“正在加载... ..”。在下载他们的数据时,UI仍然完全响应。我想要做的是下载一些Twitter数据。

这就是我现在所拥有的,但它阻止了atm:

// Constructor:

// load the twitter data
WebClient twitter = new WebClient();

twitter.DownloadStringCompleted += new DownloadStringCompletedEventHandler(twitter_DownloadStringCompleted);
twitter.DownloadStringAsync(new Uri("http://api.twitter.com/1/statuses/user_timeline.xml?screen_name=badreligion"));

// Callback function:

void twitter_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
  if (e.Error != null)
  {
    return;
  }

  XElement xmlTweets = XElement.Parse(e.Result);

  TwitterListBox.ItemsSource = from tweet in xmlTweets.Descendants("status")
                               select new TwitterItem
                               {
                                 ImageSource = tweet.Element("user").Element("profile_image_url").Value,
                                 Message = tweet.Element("text").Value,
                                 UserName = tweet.Element("user").Element("screen_name").Value
                               };

}

编辑:尝试多线程:

// in constructor
Dispatcher.BeginInvoke(new ThreadStart(StartTwitterUpdate));

// other functions
private void StartTwitterUpdate()
{
  // load the twitter data
  WebClient twitter = new WebClient();

  twitter.DownloadStringCompleted += new DownloadStringCompletedEventHandler(twitter_DownloadStringCompleted);
  twitter.DownloadStringAsync(new Uri("http://api.twitter.com/1/statuses/user_timeline.xml?screen_name=badreligion"));
}

void twitter_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
  if (e.Error != null)
  {
    return;
  }

  XElement xmlTweets = XElement.Parse(e.Result);

  TwitterListBox.ItemsSource = from tweet in xmlTweets.Descendants("status")
                               select new TwitterItem
                               {
                                 ImageSource = tweet.Element("user").Element("profile_image_url").Value,
                                 Message = tweet.Element("text").Value,
                                 UserName = tweet.Element("user").Element("screen_name").Value
                               };

}

编辑2 :按照Rico Suter的建议使用HttpWebRequest,并在this博文的帮助下,我认为我已经完成了:

// constructor
StartTwitterUpdate();


private void StartTwitterUpdate()
{
  HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(new Uri("http://api.twitter.com/1/statuses/user_timeline.xml?screen_name=badreligion"));

  request.BeginGetResponse(new AsyncCallback(twitter_DownloadStringCompleted), request);
}

void twitter_DownloadStringCompleted(IAsyncResult asynchronousResult)
{
  HttpWebRequest request = (HttpWebRequest)asynchronousResult.AsyncState;

  HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(asynchronousResult);

  using (StreamReader streamReader1 = 
    new StreamReader(response.GetResponseStream()))
    {
      string resultString = streamReader1.ReadToEnd();

      XElement xmlTweets = XElement.Parse(resultString);

      Deployment.Current.Dispatcher.BeginInvoke(() =>
      {
        TwitterListBox.ItemsSource = from tweet in xmlTweets.Descendants("status")
                                     select new TwitterItem
                                     {
                                       ImageSource = tweet.Element("user").Element("profile_image_url").Value,
                                       Message = tweet.Element("text").Value,
                                       UserName = "@" + tweet.Element("user").Element("screen_name").Value
                                     };
      });
    }
}

2 个答案:

答案 0 :(得分:5)

我认为WebClient方法部分阻塞。包括DNS查找的第一部分是阻止,但下载本身不是。

请参阅C# async methods still hang UI

我个人认为这是.net API中的一个错误(或者更糟糕的是:被设计破坏)

作为一种解决方法,您可以在单独的线程中开始下载。我建议使用任务API。

Task.Factory.StartNew(
  ()=>
  {
      twitter.DownloadStringAsync(new Uri("http://api.twitter.com/1/statuses/user_timeline.xml?screen_name=badreligion"));
  }
);

不是最佳的,因为它在执行DNS查找时占用一个线程,但在实践中应该是可接受的。


我认为你的代码的另一个问题是回调不会发生在主线程上,而是发生在线程池线程上。您需要使用将事件发布到主线程的SynchronizationContext

答案 1 :(得分:1)

您有两种选择:HttpWebRequestWebClient。这两个类都在后台下载。唯一区别:使用WebClient方法twitter_DownloadStringCompleted将在UI线程中调用,因此解析数据将阻止UI。

如果您使用HttpWebRequest,该方法将在另一个线程中调用,但要设置数据绑定的数据或直接设置为控件,您必须使用以下内容:

void twitter_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
    // do your parsing with e.Result...
    Deployment.Current.Dispatcher.BeginInvoke(() => {
        // set your data (2) to UI
    });
}

将在UI线程中调用(2)中的代码。将进度条设置为StartTwitterUpdate中可见,并在(2)中将进度条设置为不可见。

查看此类以简化http调用(POST,FILES,GZIP等):

http://mytoolkit.codeplex.com/wikipage?title=Http