如何将我的 WP7 接口绑定到我正在异步检索的数据

本文关键字:异步 检索 数据 我的 WP7 绑定 接口 | 更新日期: 2023-09-27 17:56:53

我正在开发一个Windows Phone 7应用程序,该应用程序允许用户查看其 Chargify.com 帐户下每个"站点"的统计信息。

我一直在关注一个复视线培训视频,它让我大部分时间都在那里,但是我的数据来自一个复杂的来源,他们已经硬编码了一个列表。

因此,这是设置:

模型:

 public SiteStats
 {
     public string seller_name { get; set;}
     public static GetSiteStatistics(string subdomain, string apiKey)
     {
        SiteStats retVal = null;
        HttpWebRequest request = WebRequest.Create(string.Format("https://{0}.chargify.com/stats.json", subdomain)) as HttpWebRequest;
        NetworkCredential credentials = new NetworkCredential(apiKey, "X");
        request.Credentials = credentials;
        request.Method = "GET";
        request.Accept = "application/json";
        request.BeginGetResponse(result =>
        {
            using (var response = request.EndGetResponse(result))
            {
                using (StreamReader reader = new StreamReader(response.GetResponseStream()))
                {
                    string stats = reader.ReadToEnd();
                    retVal = Json.Deserialize<SiteStats>(stats);
                }
            }
        }, request);
        return retVal;
     }
 }

视图模型:

 public class SiteDetailViewModel : ViewModelBase
 {
    private SiteStats _siteStats;
    public SiteDetailViewModel(string subdomain) : this()
    {
       this._siteStats = SiteStats.GetSiteStatistics(subdomain, "apiKeyHere");
    }
    public SiteDetailViewModel : base() { ViewName = "site details"; }
    public SiteStats SiteStats
    {
      get { return _siteStats; }
      set {
        if (_siteStats != value) {
          _siteStats = value;
          OnPropertyChanged("SiteStats");
        }
     }
 }

观点:

 public partial class SiteDetailView : PhoneApplicationPage
 {
   private SiteDetailViewModel _viewModel;
   public SiteDetailView()
   {
      InitializeComponent();
      Loaded += new RoutedEventHandler(SiteDetailView_Loaded);
   }
   void SiteDetailView_Loaded(object sender, RoutedEventArgs e)
   {
      string subdomain = NavigationContext.QueryString["subdomain"];
      _viewModel = new SiteDetailViewModel(subdomain);
      this.DataContext = _viewModel;
   }
 }

问题是,当我打电话给这个时。数据上下文 - _viewModel成员还没有数据。因此,视图数据绑定 - 但值为空。

有什么建议吗?一切正常,除了视图没有将绑定控件填充到数据中。

- 科里

如何将我的 WP7 接口绑定到我正在异步检索的数据

_viewModel应该有一个统计信息ObservableCollection<>,并将UI绑定到该集合。每当在集合中添加或删除项时,UI 都会自动更新(因为它会发出 OnPropertyChanged 事件)

你的问题不是WPF,而是GetSiteStatistics。由于您获得的结果是异步的,因此您的方法几乎总是返回 null,除非碰巧在 GetSiteStatistics 方法返回之前执行 BeginGetResponse。它在任何应用程序中都会失败。

您可以让 GetSiteStatistics 始终创建并返回一个对象,并且只在 BeginGetResponse 中填写它。但是你应该确保整个事情是线程安全的。

好吧,我想这个了

..

它一直在那里,我只是错过了它。

1)您正在异步获取数据。"请求。BeginGetResponse(result=> ...);" 在将来的某个时候发生,但您在此发生之前返回结果。代码不断移动,它不会等待您的结果。以下是您要执行的操作:

public class SiteStats
{
  public string seller_name { get; set;}
  public static void GetSiteStatistics(string subdomain, string apiKey, Action<SiteStats> callback)
  {
    SiteStats retVal = null;
    HttpWebRequest request = WebRequest.Create(string.Format("https://{0}.chargify.com/stats.json", subdomain)) as HttpWebRequest;
    NetworkCredential credentials = new NetworkCredential(apiKey, "X");
    request.Credentials = credentials;
    request.Method = "GET";
    request.Accept = "application/json";
    request.BeginGetResponse(result =>
    {
        using (var response = request.EndGetResponse(result))
        {
            using (StreamReader reader = new StreamReader(response.GetResponseStream()))
            {
                string stats = reader.ReadToEnd();
                retVal = Json.Deserialize<SiteStats>(stats);
                callback(retVal);
            }
        }
    }, request);
    //return retVal; // you can't return here
  }
}

相关的视图模型代码将如下所示:

public SiteDetailViewModel(string subdomain) : this()
{
   SiteStats.GetSiteStatistics(subdomain, "apiKeyHere", (result)=> {
     // Note you may need to wrap this in a Dispatcher call 
     // as you may be on the wrong thread to update the UI 
     // if that happens you'll get a cross thread access 
     // you will have to expose the dispatcher through some 
     // other mechanism. One way to do that would be a static
     // on your application class which we'll emulate and 
     // I'll give you the code in a sec
     myRootNamespace.App.Dispatcher.BeginInvoke(()=>this._siteStats = results);
   });
}

以下是您需要对应用程序类进行的更改(我不确定这有多线程安全,我真的建议您使用 MVVMLight 的 DispatcherHelper 之类的东西。

public partial class App : Application
{
    public static Dispatcher Dispatcher { get; private set; } // Add this line!!
    // More code follows we're skipping it
    private void Application_Startup(object sender, StartupEventArgs e)
    {
        this.RootVisual = new MainPage(); 
        Dispatcher = this.RootVisual.Dispatcher; // only add this line!!
    }
    private void Application_Exit(object sender, EventArgs e)
    {
        // Do this to clean up
        Dispatcher = null;
    }
}