代码之家  ›  专栏  ›  技术社区  ›  JamesStuddart

WP7中的异步调用

  •  6
  • JamesStuddart  · 技术社区  · 15 年前

    我今天一直在试验WP7应用程序,并且遇到了一些困难。 我喜欢在用户界面和主要应用程序代码之间进行分离,但我遇到了困难。

    我已经成功地实现了一个WebClient请求并得到了一个结果,但是由于调用是异步的,我不知道如何将这个备份传递到UI级别。我似乎无法插手等待响应完成或任何事情。 我一定是做错了什么。

    (这是我在网站上下载的Xbox360语音库: http://www.jamesstuddart.co.uk/Projects/ASP.Net/Xbox_Feeds/ 我将移植到WP7作为测试)

    下面是后端代码段:

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

    这是前端代码:

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

    现在我明白了我需要放点东西进去 ClientDownloadStringCompleted 但我不确定是什么。

    4 回复  |  直到 14 年前
        1
  •  6
  •   AnthonyWJones    15 年前

    问题是,一旦将异步操作引入到代码路径中,整个代码路径就需要变成异步的。

    • 因为 GetResponse 电话 DownloadStringAsync 它必须是异步的,不能返回字符串,只能在回调时执行。
    • 因为 GetGamer 电话 回应指令 它现在是异步的,不能返回 XboxGamer ,它只能在回调时执行此操作
    • 因为 GetGamerDetails 电话 游戏玩家 它现在是异步的,不能在调用后继续其代码,只能在收到来自的调用后才能继续。 游戏玩家 .
    • 因为 获取详细信息 现在是异步的,任何调用都必须承认这种行为。
    • …这将一直持续到发生用户事件的链的顶部。

    下面是一些空代码,它将一些异步性引入到代码中。

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

    正如您所看到的,异步编程可能会变得非常混乱。

        2
  •  2
  •   driis    15 年前

    你通常有两种选择。您也可以将后端代码公开为异步API,或者需要等待在getResponse中完成调用。

    以异步方式执行这一操作意味着在一个地方启动流程,然后返回,并在数据可用时更新UI。这通常是首选的方法,因为在UI线程上调用阻塞方法会使应用程序在该方法运行时看起来没有响应。

        3
  •  1
  •   John Vert    15 年前

    我认为“Silverlight方式”应该是 databinding . XboxGamer对象应实现 INotifyPropertyChanged 接口。当您调用getgamer()时,它会立即返回一个“空”的XboxGamer对象(可能带有gamertag==“正在加载…”或其他东西)。在ClientDownloadStringCompleted处理程序中,应反序列化返回的XML,然后激发InotifyPropertyChanged.PropertyChanged事件。

    如果您查看sdk中的“Windows Phone数据绑定应用程序”项目模板,则通过这种方式实现itemViewModel类。

        4
  •  0
  •   Nikos Baxevanis    15 年前

    Here 是如何向WP7上的任何类型公开异步功能的。