来自 JSON 的 UWP 数据绑定不工作
UWP Databinding from JSON not working
我正在尝试使用 JSON.NET 从 json url 填充网格。我已经能够反序列化 url 中的数据并将其绑定到模型 class。但是它不绑定到 XAML 页面。
这是我的模型 class 和 MovieManger class:
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
namespace DataBindingTest3.Models
{
public class AmgMovie
{
public string state { get; set; }
public Data data { get; set; }
}
public class Data
{
public int type { get; set; }
public string type_name { get; set; }
public Movie[] movies { get; set; }
}
public class Movie
{
public string id { get; set; }
public string title { get; set; }
public string movie_desc { get; set; }
public string movie_actors { get; set; }
public string movie_director { get; set; }
public string music_director { get; set; }
public string movie_year { get; set; }
public string movie_month { get; set; }
public string realeased_date { get; set; }
public string image { get; set; }
public string portrait_image { get; set; }
public string movie_list_image_url { get; set; }
public string movie_poster_url { get; set; }
public string duration { get; set; }
public string url { get; set; }
public string download_url { get; set; }
public string trailer_url { get; set; }
public int allow_download { get; set; }
}
public class MovieManager
{
public static async Task<List<Movie>> GetMovies()
{
var movies = new List<Movie>();
var amg = new HttpClient();
HttpResponseMessage response = await amg.GetAsync(new Uri("some URL"));
var json = await response.Content.ReadAsStringAsync();
AmgMovie Movie = JsonConvert.DeserializeObject<AmgMovie>(json);
for (uint i = 0; i < Movie.data.movies.Count(); i++)
{
string id1 = Movie.data.movies[i].id;
string title1 = Movie.data.movies[i].title;
string portrait_image1 = Movie.data.movies[i].portrait_image;
movies.Add(new Movie { id = id1, title = title1, portrait_image = portrait_image1 });
}
return movies;
}
}
}
这是 XAML 页面的隐藏代码:
public sealed partial class MainPage : Page
{
private List<Movie> Movie;
public MainPage()
{
this.InitializeComponent();
}
private async void Page_Loaded(object sender, RoutedEventArgs e)
{
Movie = await MovieManager.GetMovies();
}
}
这是 XAML 页面标记:
<Page
x:Class="DataBindingTest3.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:DataBindingTest3"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:data="using:DataBindingTest3.Models"
Loaded="Page_Loaded"
mc:Ignorable="d">
<Page.Resources>
<DataTemplate x:DataType="data:Movie" x:Key="MovieDataTemplate">
<StackPanel>
<TextBlock x:Name="movieID" Text="{x:Bind id}" FontSize="12" Foreground="Black" />
<Image x:Name="moviePoster" Source="{x:Bind portrait_image}" Width="145" Height="214"/>
<TextBlock x:Name="movieName" Text="{x:Bind title}" FontSize="16" Foreground="Black"/>
</StackPanel>
</DataTemplate>
</Page.Resources>
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="100" />
</Grid.RowDefinitions>
<GridView Grid.Row="0" ItemsSource="{x:Bind Movie}" ItemTemplate="{StaticResource MovieDataTemplate}">
</GridView>
</Grid>
</Page>
我也尝试过在没有 json 的情况下进行绑定,只是在 MovieManager class 中输入一些示例数据,它完美地绑定了。我注意到,在调试示例方法和 json 方法时,这两种方法都有 returns 数据,但是只有当我使用示例数据时,调试器才会进入 XAML Page.g.cs绑定数据。
您需要将 Movie 集合设为 ObservableCollection 而不仅仅是 List。
你有两个选择:
在 MainPage.xaml.cs 中,将 Movie 字段的类型更改为可观察集合,并将 GetMovies() 函数结果的项目复制到集合中,如下所示:(UI 更改如果 Movies 集合的内容发生变化(add/remove 个元素))
private ObservableCollection<Movie> Movies = new ObservableCollection<Movie>();
private async void AboutPage_Loaded(object sender, RoutedEventArgs e)
{
foreach (var movie in await GetMovies())
{
Movie.Add(movie);
}
}
您使用 INotifyPropertyChanged 实现为电影列表创建 属性,并将 x:Bind 模式更改为单向模式:(UI 如果电影 属性 改变了(而不是它的内容))
public sealed partial class MainPage : Page, INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private List<Movie> _movies;
public List<Movie> Movies
{
get { return _movies; }
set { if(value != _movies) { _movies = value; PropertyChanged?.Invoke(nameof(Movies)); } }
}
public MainPage()
{
this.InitializeComponent();
}
private async void Page_Loaded(object sender, RoutedEventArgs e)
{
Movies = await MovieManager.GetMovies();
}
}
Xaml:
<GridView Grid.Row="0" ItemsSource="{x:Bind Movies, Mode=OneWay}" ItemTemplate="{StaticResource MovieDataTemplate}" />
在第一个版本中,如果您用新列表覆盖电影,UI 不会改变。
在第二个版本中,如果您将 add/remove 个元素添加到列表中,UI 将不会改变。
您可以合并这两个版本。
我正在尝试使用 JSON.NET 从 json url 填充网格。我已经能够反序列化 url 中的数据并将其绑定到模型 class。但是它不绑定到 XAML 页面。 这是我的模型 class 和 MovieManger class:
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
namespace DataBindingTest3.Models
{
public class AmgMovie
{
public string state { get; set; }
public Data data { get; set; }
}
public class Data
{
public int type { get; set; }
public string type_name { get; set; }
public Movie[] movies { get; set; }
}
public class Movie
{
public string id { get; set; }
public string title { get; set; }
public string movie_desc { get; set; }
public string movie_actors { get; set; }
public string movie_director { get; set; }
public string music_director { get; set; }
public string movie_year { get; set; }
public string movie_month { get; set; }
public string realeased_date { get; set; }
public string image { get; set; }
public string portrait_image { get; set; }
public string movie_list_image_url { get; set; }
public string movie_poster_url { get; set; }
public string duration { get; set; }
public string url { get; set; }
public string download_url { get; set; }
public string trailer_url { get; set; }
public int allow_download { get; set; }
}
public class MovieManager
{
public static async Task<List<Movie>> GetMovies()
{
var movies = new List<Movie>();
var amg = new HttpClient();
HttpResponseMessage response = await amg.GetAsync(new Uri("some URL"));
var json = await response.Content.ReadAsStringAsync();
AmgMovie Movie = JsonConvert.DeserializeObject<AmgMovie>(json);
for (uint i = 0; i < Movie.data.movies.Count(); i++)
{
string id1 = Movie.data.movies[i].id;
string title1 = Movie.data.movies[i].title;
string portrait_image1 = Movie.data.movies[i].portrait_image;
movies.Add(new Movie { id = id1, title = title1, portrait_image = portrait_image1 });
}
return movies;
}
}
}
这是 XAML 页面的隐藏代码:
public sealed partial class MainPage : Page
{
private List<Movie> Movie;
public MainPage()
{
this.InitializeComponent();
}
private async void Page_Loaded(object sender, RoutedEventArgs e)
{
Movie = await MovieManager.GetMovies();
}
}
这是 XAML 页面标记:
<Page
x:Class="DataBindingTest3.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:DataBindingTest3"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:data="using:DataBindingTest3.Models"
Loaded="Page_Loaded"
mc:Ignorable="d">
<Page.Resources>
<DataTemplate x:DataType="data:Movie" x:Key="MovieDataTemplate">
<StackPanel>
<TextBlock x:Name="movieID" Text="{x:Bind id}" FontSize="12" Foreground="Black" />
<Image x:Name="moviePoster" Source="{x:Bind portrait_image}" Width="145" Height="214"/>
<TextBlock x:Name="movieName" Text="{x:Bind title}" FontSize="16" Foreground="Black"/>
</StackPanel>
</DataTemplate>
</Page.Resources>
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="100" />
</Grid.RowDefinitions>
<GridView Grid.Row="0" ItemsSource="{x:Bind Movie}" ItemTemplate="{StaticResource MovieDataTemplate}">
</GridView>
</Grid>
</Page>
我也尝试过在没有 json 的情况下进行绑定,只是在 MovieManager class 中输入一些示例数据,它完美地绑定了。我注意到,在调试示例方法和 json 方法时,这两种方法都有 returns 数据,但是只有当我使用示例数据时,调试器才会进入 XAML Page.g.cs绑定数据。
您需要将 Movie 集合设为 ObservableCollection 而不仅仅是 List。
你有两个选择:
在 MainPage.xaml.cs 中,将 Movie 字段的类型更改为可观察集合,并将 GetMovies() 函数结果的项目复制到集合中,如下所示:(UI 更改如果 Movies 集合的内容发生变化(add/remove 个元素))
private ObservableCollection<Movie> Movies = new ObservableCollection<Movie>(); private async void AboutPage_Loaded(object sender, RoutedEventArgs e) { foreach (var movie in await GetMovies()) { Movie.Add(movie); } }
您使用 INotifyPropertyChanged 实现为电影列表创建 属性,并将 x:Bind 模式更改为单向模式:(UI 如果电影 属性 改变了(而不是它的内容))
public sealed partial class MainPage : Page, INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; private List<Movie> _movies; public List<Movie> Movies { get { return _movies; } set { if(value != _movies) { _movies = value; PropertyChanged?.Invoke(nameof(Movies)); } } } public MainPage() { this.InitializeComponent(); } private async void Page_Loaded(object sender, RoutedEventArgs e) { Movies = await MovieManager.GetMovies(); } }
Xaml:
<GridView Grid.Row="0" ItemsSource="{x:Bind Movies, Mode=OneWay}" ItemTemplate="{StaticResource MovieDataTemplate}" />
在第一个版本中,如果您用新列表覆盖电影,UI 不会改变。 在第二个版本中,如果您将 add/remove 个元素添加到列表中,UI 将不会改变。
您可以合并这两个版本。