Xamarin.Forms:如何从Web API数据填充饼图?

今天是个好日子。 我正在创建一个Xamarin.Forms便携式应用程序。 我目前正在编写一个包含静态数据的 PieChart(OxyPlot)。

我想要做的是在我拥有的每个Pie Slice中都有一个动态数据 。 意思是,数据应来自我的数据库。

我已经能够从我的数据库中检索数据并将其显示为我正在使用Web Api创建的移动应用程序中的List ,如下所示:

ClientListPage.xaml

                   

ClientListPage.xaml.cs

 using Newtonsoft.Json; using OxyPlot; using OxyPlot.Series; using System; using System.Collections.Generic; using System.Linq; using System.Net.Http; using System.Net.Http.Headers; using System.Text; using System.Threading.Tasks; using System.Windows.Input; using Xamarin.Forms; using XamarinFormsDemo.Models; using XamarinFormsDemo.ViewModels; namespace XamarinFormsDemo.Views { public partial class ClientListPage : ContentPage { CustomerVM viewModel; public ClientListPage() { NavigationPage.SetHasNavigationBar(this, true); InitializeComponent(); viewModel = new CustomerVM(); BindingContext = viewModel; } async override protected void OnAppearing() { base.OnAppearing(); var json = await GetCustomerAsync(); var customers = JsonConvert.DeserializeObject(json); foreach (Customer c in customers) viewModel.CustomerList.Add(c); } async Task GetCustomerAsync() { var client = new HttpClient(); client.BaseAddress = new Uri("http://192.168.1.11:50857/"); client.DefaultRequestHeaders.Accept.Clear(); client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); HttpResponseMessage response = await client.GetAsync("api/Customer"); if (response.IsSuccessStatusCode) { return await response.Content.ReadAsStringAsync(); } else return response.ReasonPhrase; } } } 

CustomerVM.cs

 using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; using System.Diagnostics; using System.Linq; using System.Net.Http; using System.Runtime.CompilerServices; using System.Text; using System.Threading.Tasks; using System.Windows.Input; using Xamarin.Forms; using XamarinFormsDemo.Models; using XamarinFormsDemo.Services; using XamarinFormsDemo.Views; namespace XamarinFormsDemo.ViewModels { public class CustomerVM : INotifyPropertyChanged { private ObservableCollection _customerList; // keep all customers private ObservableCollection _searchedCustomerList; // keep a copy for searching private Customer _selectedCustomer = new Customer(); private string _keyword = ""; public string Keyword { get { return _keyword; } set { this._keyword = value; // while keyword changed we filter Employees //Filter(); } } public ObservableCollection CustomerList { get { return _customerList; } set { _customerList = value; OnPropertyChanged(); } } public CustomerVM() { CustomerList = new ObservableCollection(); } public event PropertyChangedEventHandler PropertyChanged; protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) { var handler = PropertyChanged; if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName)); } } } 

但这一次,我需要在PieChart中完成。

我真的不知道该怎么做。 但我认为我从上面的WEB API中检索数据的方式与我在图表中如何做到这一点有相似之处。 希望您能够帮助我。

非常感谢。 这些是我的一些代码:

SalesPerProductViewModel.cs

 using OxyPlot; using OxyPlot.Annotations; using OxyPlot.Axes; using OxyPlot.Series; using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; using System.Linq; using System.Runtime.CompilerServices; using System.Text; using System.Threading.Tasks; using XamarinFormsDemo.Models; namespace XamarinFormsDemo.ViewModels { public class SalesPerProductViewModel : INotifyPropertyChanged { private ObservableCollection _salesList; // keep all customers public ObservableCollection SalesPerProductModel { get { return _salesList; } set { _salesList = value; OnPropertyChanged(); } } public SalesPerProductViewModel() { SalesPerProductModel = new ObservableCollection(); } public event PropertyChangedEventHandler PropertyChanged; protected void OnPropertyChanged([CallerMemberName] string propertyName = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } } } 

SalesPerProductPage.xaml (这是应该显示动态图表的位置)

       

SalesPerProductPage.xaml.cs

 using OxyPlot; using OxyPlot.Xamarin.Forms; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using XamarinFormsDemo.ViewModels; using Xamarin.Forms; using XamarinFormsDemo.Models; using Newtonsoft.Json; using System.Net.Http; using System.Net.Http.Headers; using OxyPlot.Series; namespace XamarinFormsDemo.Views { public partial class SalesPerProductPage : ContentPage { private PlotModel modelForSales; SalesPerProductViewModel viewModelforSales; public SalesPerProductPage() { InitializeComponent(); viewModelforSales = new SalesPerProductViewModel(); BindingContext = viewModelforSales; } //end of SalesPerProductPage() async override protected void OnAppearing() { base.OnAppearing(); var json = await GetSalesPerProductAsync(); var salesPerProduct = JsonConvert.DeserializeObject(json); modelForSales = new PlotModel { Title = "Sales Per Product", TitleColor = OxyColors.Teal, TitleFontSize = 30, TextColor = OxyColors.White, DefaultFont = "Arial Black", DefaultFontSize = 20 }; dynamic seriesP2 = new PieSeries { StrokeThickness = 2.0, InsideLabelPosition = 0.8, AngleSpan = 360, StartAngle = 0 }; foreach (Sales c in salesPerProduct) { seriesP2.Slices.Add(new PieSlice(c.PRODUCT_CODE, c.PRODUCT_ID) { IsExploded = false, Fill = OxyColors.Teal }); } modelForSales.Series.Add(seriesP2); this.SalesPerProductModel = modelForSales; } public PlotModel SalesPerProductModel { get; private set; } async Task GetSalesPerProductAsync() { var client = new HttpClient(); client.BaseAddress = new Uri("http://192.168.1.11:50857/"); client.DefaultRequestHeaders.Accept.Clear(); client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); HttpResponseMessage response = await client.GetAsync("api/Sales"); if (response.IsSuccessStatusCode) { return await response.Content.ReadAsStringAsync(); } else return response.ReasonPhrase; } } } 

Sales.cs

 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace XamarinFormsDemo.Models { public class Sales { public int Id { get; set; } public int ORDER_ID { get; set; } public int ORDER_DETAILS_ID { get; set; } public int PRODUCT_ID { get; set; } public string PRODUCT_CODE { get; set; } public string NET_AMOUNT { get; set; } } } 

您正在将PlotModel分配给局部变量。 您必须将其分配给ViewModel 。 这是您重构的工作代码:

SalesPerProductPage.xaml:

       

SalesPerProductPage.xaml.cs:

 public partial class SalesPerProductPage : ContentPage { public SalesPerProductViewModel viewModelforSales { get; set; } public SalesPerProductPage() { InitializeComponent(); viewModelforSales = new SalesPerProductViewModel(); BindingContext = viewModelforSales; } async protected override void OnAppearing() { base.OnAppearing(); var json = await GetSalesPerProductAsync(); var salesPerProduct = JsonConvert.DeserializeObject(json); PlotModel modelForSales = new PlotModel { Title = "Sales Per Product", TitleColor = OxyColors.Teal, TitleFontSize = 30, TextColor = OxyColors.White, DefaultFont = "Arial Black", DefaultFontSize = 20 }; dynamic seriesP2 = new PieSeries { StrokeThickness = 2.0, InsideLabelPosition = 0.8, AngleSpan = 360, StartAngle = 0, FontSize = 24 }; foreach (Sales c in salesPerProduct) { seriesP2.Slices.Add(new PieSlice(c.PRODUCT_CODE, c.PRODUCT_ID)); } modelForSales.Series.Add(seriesP2); viewModelforSales.SalesPerProductModel = modelForSales; } async Task GetSalesPerProductAsync() { var client = new HttpClient(); client.BaseAddress = new Uri("http://10.0.0.17:64550/"); client.DefaultRequestHeaders.Accept.Clear(); client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); HttpResponseMessage response = await client.GetAsync("api/Sales"); if (response.IsSuccessStatusCode) { return await response.Content.ReadAsStringAsync(); } else return response.ReasonPhrase; } } 

SalesPerProductViewModel:

 public class SalesPerProductViewModel : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged = delegate { }; private PlotModel _salesPerProductModel; public PlotModel SalesPerProductModel { get { return _salesPerProductModel; } set { if (value != _salesPerProductModel) { _salesPerProductModel = value; PropertyChanged(this, new PropertyChangedEventArgs("SalesPerProductModel")); } } } public SalesPerProductViewModel() { } } 

在此处输入图像描述

解析json并填充列表以进入listview时,可以在viewmodel中填充系列。 获得Customer对象列表后,请浏览它们并使用它们的数据创建饼图切片。

以下内容:

  var json = await GetCustomerAsync(); var customers = JsonConvert.DeserializeObject(json); dynamic seriesP1 = new PieSeries { StrokeThickness = 2.0, InsideLabelPosition = 0.8, AngleSpan = 360, StartAngle = 0 }; foreach (Customer c in customers) { seriesP1.Slices.Add(new PieSlice(c.CustomerName, c.SomeValue) { IsExploded = false, Fill = OxyColors.Teal }); } 

我不知道您的Customer类是什么样的,您想要显示什么值,等等。请记住这一点。 这只是我的意思的一个例子。 此外,构建您的代码,以便您只进行一次Http调用,然后使用该列表和图表的客户列表,不要下载数据两次只是为了以两种不同的方式显示它。