2010-10-02 62 views
6

Tôi đã thử nghiệm với các ứng dụng WP7 ngày hôm nay và đã đạt được một chút tường. Tôi muốn có sự tách biệt giữa giao diện người dùng và mã ứng dụng chính nhưng Ive đã đâm vào tường.Cuộc gọi không đồng bộ trong WP7

Tôi đã thực hiện thành công yêu cầu webclient và nhận kết quả, nhưng vì cuộc gọi không đồng bộ, tôi không biết cách chuyển bản sao lưu này sang cấp UI. Tôi dường như không thể hack trong một chờ đợi để đáp ứng để hoàn thành hoặc bất cứ điều gì. Tôi phải làm điều gì sai.

(đây là thư viện xbox360Voice rằng tôi có để tải về trên trang web của tôi: http://www.jamesstuddart.co.uk/Projects/ASP.Net/Xbox_Feeds/ mà tôi đang porting để WP7 như một thử nghiệm)

đây là đoạn mã backend:

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; 
     } 
    } 

và điều này là mã giao diện người dùng:

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"; 
    } 
} 

Bây giờ tôi hiểu rằng tôi cần đặt thứ gì đó trong ClientDownloadStringCompleted nhưng tôi không chắc chắn về điều gì.

Trả lời

6

Sự cố bạn gặp phải là ngay sau khi thao tác không đồng bộ được đưa vào đường dẫn mã, toàn bộ đường dẫn mã cần phải trở thành không đồng bộ.

  • GetResponse cuộc gọi DownloadStringAsync nó phải trở thành đồng bộ, nó không thể trở về một chuỗi, nó chỉ có thể làm điều đó trên một callback
  • GetGamer cuộc gọi GetResponse mà bây giờ là không đồng bộ nó không thể trở về một XboxGamer, nó chỉ có thể thực hiện điều đó khi gọi lại
  • GetGamerDetails cuộc gọi GetGamer hiện không đồng bộ không thể tiếp tục mã sau cuộc gọi, nó chỉ có thể thực hiện sau khi nhận được cuộc gọi từ GetGamer.
  • Bởi vì GetGamerDetails hiện không đồng bộ bất cứ điều gì gọi nó cũng phải thừa nhận hành vi này.
  • .... điều này tiếp tục tất cả các con đường lên đến đỉnh của chuỗi nơi sự kiện của người dùng sẽ xảy ra.

Dưới đây là một số mã không khí đánh bật một số sự đồng bộ trong mã.

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";    
    }   
} 

Như bạn có thể thấy chương trình không đồng bộ có thể thực sự lộn xộn.

+0

"Như bạn có thể thấy lập trình không đồng bộ có thể nhận được thực sự lộn xộn." ... đó là một lý do để sử dụng F #. Với F #, bạn có thể cấu trúc lại mã thành async mà không cần phải thực hiện tất cả các nhào lộn lỗi kiểm soát ngược lại. – Brian

+0

@Brian: Tôi hoàn toàn đồng ý. Tôi chỉ muốn chương trình chức năng có thể được thực hiện dễ tiếp cận hơn, nó có thể là để tâm trí trẻ hơn nhưng không có vấn đề làm thế nào tôi cố gắng tôi không thể có được các khái niệm để dính vào tôi. – AnthonyWJones

+0

bệnh cho ngày mai đi nhờ – JamesStuddart

2

Bạn thường có 2 tùy chọn. Hoặc bạn cũng hiển thị mã phụ trợ của mình dưới dạng API không đồng bộ hoặc bạn cần đợi cuộc gọi hoàn tất trong GetResponse.

Làm theo cách không đồng bộ sẽ có nghĩa là bắt đầu quá trình một địa điểm, sau đó quay lại và cập nhật giao diện người dùng khi có dữ liệu. Đây thường là cách ưa thích, vì việc gọi phương thức chặn trên chuỗi giao diện người dùng sẽ khiến ứng dụng của bạn có vẻ không phản hồi miễn là phương thức đang chạy.

+0

Bạn có bất kỳ ví dụ nào về điều này không, vì tôi hiểu 'cách tôi có thể thực hiện' nhưng tôi không biết cách triển khai. Tôi havent thực hiện bất kỳ SL trước khi hoặc như vậy Im trên một đường cong học tập dốc. – JamesStuddart

1

Tôi nghĩ rằng "Cách Silverlight" sẽ là sử dụng databinding. Đối tượng XboxGamer của bạn nên triển khai giao diện INotifyPropertyChanged. Khi bạn gọi GetGamer() nó trả về ngay lập tức với một đối tượng XboxG "trống" (có thể với GamerTag == "Đang tải ..." hoặc một cái gì đó). Trong trình xử lý ClientDownloadStringCompleted của bạn, bạn nên deserialize XML đã trả về và sau đó kích hoạt sự kiện INotifyPropertyChanged.PropertyChanged.

Nếu bạn nhìn vào mẫu dự án "Windows Phone Databound Application" trong SDK, lớp ItemViewModel được triển khai theo cách này.

+0

Cảm ơn, điều này có vẻ như những gì tôi có thể đang tìm kiếm. Tôi đã xem xét các mẫu (như trong nhìn vào nó trong cửa sổ 'dự án mới', nhưng không tạo ra một) Ill cho nó một đi. – JamesStuddart

0

Here là cách bạn có thể hiển thị các tính năng không đồng bộ với bất kỳ loại nào trên WP7.

Các vấn đề liên quan