【问题标题】:Async calls in WP7WP7 中的异步调用
【发布时间】:2010-10-02 14:40:09
【问题描述】:

我今天一直在尝试使用 WP7 应用程序,但遇到了一些困难。 我喜欢将 UI 和主应用代码分开,但我碰壁了。

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

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

这里是后端代码sn-p:

    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 中放置一些东西,但我不确定是什么。

【问题讨论】:

    标签: asynchronous windows-phone-7


    【解决方案1】:

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

    • 因为GetResponse 调用DownloadStringAsync 它必须变成异步的,它不能返回一个字符串,它只能在回调中做到这一点
    • 因为GetGamer 调用GetResponse 现在是异步的,所以它不能返回XboxGamer,它只能在回调时这样做
    • 因为 GetGamerDetails 调用 GetGamer 现在是异步的,所以它无法在调用后继续执行其代码,它只能在收到来自 GetGamer 的回调后才能执行此操作。
    • 因为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";              
        }         
    }
    

    如您所见,异步编程会变得非常混乱。

    【讨论】:

    • “正如你所见,异步编程会变得非常混乱。” ...这是使用 F# 的原因之一。使用 F#,您可以将代码重构为异步,而无需进行所有的回调控制反转。
    • @Brian:我完全同意。我只是希望函数式编程可以更容易理解,这可能是年轻人的想法,但无论我多么努力,我都无法让这些概念牢牢记住。
    • +100 非常感谢您节省了我的时间...!!在对特定 URL 进行 Web 服务调用时正在搜索传递的用户名/密码,我在这里得到了它。谢谢
    【解决方案2】:

    您通常有 2 个选项。要么将后端代码也公开为异步 API,要么需要在 GetResponse 中等待调用完成。

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

    【讨论】:

    • 你有这方面的任何例子吗,据我所知“我怎么能做到”,但我不知道如何实现它。我之前也没有做过任何 SL,所以我的学习曲线很陡。
    【解决方案3】:

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

    如果你看SDK中的“Windows Phone Databound Application”项目模板,ItemViewModel类就是这样实现的。

    【讨论】:

    • 谢谢,这看起来像我可能要找的。我确实看过模板(就像在“新项目”窗口中看过它一样,但没有创建模板)我会试一试。
    【解决方案4】:

    Here 是您可以向 WP7 上的任何类型公开异步功能的方法。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-04-03
      • 1970-01-01
      • 2011-09-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-24
      相关资源
      最近更新 更多