Asynchronous calls in WP7

Today I experimented with WP7 applications and came across a wall a bit. I like the separation between the user interface and the main application code, but I hit the wall.

I successfully executed the webclient request and got the result, but since the isync call, I don’t know how to transfer this backup to the user interface level. I can’t hack while waiting for an answer to everything or something else. I have to do something wrong.

(this is the xbox360Voice library that I have to download on my website: http://www.jamesstuddart.co.uk/Projects/ASP.Net/Xbox_Feeds/ , which I port to WP7 as a test)

here is a snippet of code:

internal const string BaseUrlFormat = "http://www.360voice.com/api/gamertag-profile.asp?tag={0}"; internal static string ResponseXml { get; set; } internal static WebClient Client = new WebClient(); public static XboxGamer? GetGamer(string gamerTag) { var url = string.Format(BaseUrlFormat, gamerTag); var response = GetResponse(url, null, null); return SerializeResponse(response); } internal static XboxGamer? SerializeResponse(string response) { if (string.IsNullOrEmpty(response)) { return null; } var tempGamer = new XboxGamer(); var gamer = (XboxGamer)SerializationMethods.Deserialize(tempGamer, response); return gamer; } internal static string GetResponse(string url, string userName, string password) { if (!string.IsNullOrEmpty(userName) && !string.IsNullOrEmpty(password)) { Client.Credentials = new NetworkCredential(userName, password); } try { Client.DownloadStringCompleted += ClientDownloadStringCompleted; Client.DownloadStringAsync(new Uri(url)); return ResponseXml; } catch (Exception ex) { return null; } } internal static void ClientDownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e) { if (e.Error == null) { ResponseXml = e.Result; } } 

and this is the front end code:

 public void GetGamerDetails() { var xboxManager = XboxFactory.GetXboxManager("DarkV1p3r"); var xboxGamer = xboxManager.GetGamer(); if (xboxGamer.HasValue) { var profile = xboxGamer.Value.Profile[0]; imgAvatar.Source = new BitmapImage(new Uri(profile.ProfilePictureMiniUrl)); txtUserName.Text = profile.GamerTag; txtGamerScore.Text = int.Parse(profile.GamerScore).ToString("G 0,000"); txtZone.Text = profile.PlayerZone; } else { txtUserName.Text = "Failed to load data"; } } 

Now I understand that I need to put something in ClientDownloadStringCompleted , but I'm not sure what.

+6
asynchronous windows-phone-7
source share
4 answers

The problem is that as soon as an asynchronous operation is entered into the code path, the entire code path should become asynchronous.

  • Since GetResponse calls DownloadStringAsync , it must become asynchronous, it cannot return a string, it can only do this with a callback
  • Since GetGamer calls GetResponse , which is now asynchronous, it cannot return XboxGamer , it can only do this with a callback
  • Since GetGamerDetails calls GetGamer , which is now asynchronous, it cannot continue its code after the call, it can only do this after it receives the callback from GetGamer .
  • Since GetGamerDetails now asynchronous, all calls must also recognize this behavior.
  • .... this continues all the way to the top of the chain where the user event will occur.

Here is some kind of air code that causes some code asynchrony.

 public static void GetGamer(string gamerTag, Action<XboxGamer?> completed) { var url = string.Format(BaseUrlFormat, gamerTag); var response = GetResponse(url, null, null, (response) => { completed(SerializeResponse(response)); }); } internal static string GetResponse(string url, string userName, string password, Action<string> completed) { WebClient client = new WebClient(); if (!string.IsNullOrEmpty(userName) && !string.IsNullOrEmpty(password)) { client.Credentials = new NetworkCredential(userName, password); } try { client.DownloadStringCompleted += (s, args) => { // Messy error handling needed here, out of scope completed(args.Result); }; client.DownloadStringAsync(new Uri(url)); } catch { completed(null); } } public void GetGamerDetails() { var xboxManager = XboxFactory.GetXboxManager("DarkV1p3r"); xboxManager.GetGamer( (xboxGamer) => { // Need to move to the main UI thread. Dispatcher.BeginInvoke(new Action<XboxGamer?>(DisplayGamerDetails), xboxGamer); }); } void DisplayGamerDetails(XboxGamer? xboxGamer) { if (xboxGamer.HasValue) { var profile = xboxGamer.Value.Profile[0]; imgAvatar.Source = new BitmapImage(new Uri(profile.ProfilePictureMiniUrl)); txtUserName.Text = profile.GamerTag; txtGamerScore.Text = int.Parse(profile.GamerScore).ToString("G 0,000"); txtZone.Text = profile.PlayerZone; } else { txtUserName.Text = "Failed to load data"; } } 

As you can see, asynchronous programming can become really messy.

+6
source share

You usually have 2 options. Either you expose your internal code as an asynchronous API, or you need to wait for the call to GetResponse to complete.

Performing this asynchronous method means starting the process in one place, then returning and updating the user interface if there is data. This is usually the preferred method, since calling the lock method in the UI thread will make your application look unresponsive as long as this method executes.

+2
source share

I think the Silverlight Way will use data binding . Your XboxGamer object must implement the INotifyPropertyChanged interface. When you call GetGamer (), it immediately returns with an "empty" XboxGamer object (possibly with GamerTag == "Loading ..." or something else). In the ClientDownloadStringCompleted handler, you must deserialize the returned XML and then fire the INotifyPropertyChanged.PropertyChanged event.

If you look at the “Windows Phone Databound Application” project template in the SDK, the ItemViewModel class will be implemented this way.

+1
source share

It describes how you can expose asynchronous functions to any type of WP7.

0
source share

All Articles