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调用,然后使用该列表和图表的客户列表,不要下载数据两次只是为了以两种不同的方式显示它。
- 防止在.NET Azure Web Api中使用PATCH覆盖某些字段
- ASP NET Web API中的路由 – 适用于不同版本的API
- ASP.NET Web API MVC 4中具有特殊字符的自定义参数名称
- PUT和Delete不能与Windows Azure上的ASP.NET WebAPI和数据库一起使用
- 如何在Web Api Post请求Json中检测重复键
- ASP.NET Web API:如果从资源设置错误消息,则模型有效
- Json.Net DeserializeObject失败,只有OData.Delta – 整数
- Ninject不解析OWIN的依赖关系
- 如何使用Web API Get方法返回图像