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

标签 c# asp.net-web-api xamarin charts xamarin.forms

大家好。我正在创建 Xamarin.Forms 可移植应用程序。我目前正在编写包含静态数据的饼图 (OxyPlot)。

我想做的是在我拥有的每个饼图切片中都有一个动态数据。意思是,数据应该来 self 的数据库。

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

ClientListPage.xaml

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="XamarinFormsDemo.Views.ClientListPage"
             xmlns:ViewModels="clr-namespace:XamarinFormsDemo.ViewModels;assembly=XamarinFormsDemo"
             xmlns:controls="clr-namespace:ImageCircle.Forms.Plugin.Abstractions;assembly=ImageCircle.Forms.Plugin.Abstractions"
             BackgroundImage="bg3.jpg"
             Title="Client List1">


<StackLayout>

  <SearchBar Placeholder="Search" Text="{Binding Keyword}" SearchCommand="{Binding SearchCommand}" x:Name="txtSearch" />

    <ListView ItemsSource="{Binding CustomerList, Mode=TwoWay}"
              HasUnevenRows="True"
              IsPullToRefreshEnabled="True"
              x:Name="listView">


      <ListView.ItemTemplate>
        <DataTemplate>
          <ViewCell>
            <Grid Padding="10" RowSpacing="10" ColumnSpacing="5">
              <Grid.RowDefinitions>
                <RowDefinition Height="Auto"/>
                <RowDefinition Height="*"/>
              </Grid.RowDefinitions>
              <Grid.ColumnDefinitions>
                <ColumnDefinition Width="Auto"/>
                <ColumnDefinition Width="*"/>
              </Grid.ColumnDefinitions>

              <controls:CircleImage Source="icon.png"
                     HeightRequest="66"
                     HorizontalOptions="CenterAndExpand"
                     Aspect="AspectFill"
                     WidthRequest="66"
                     Grid.RowSpan="2"
                   />




              <Label Grid.Column="1"
                     Text="{Binding CUSTOMER_NAME}"
                     TextColor="#24e97d"
                     FontSize="24"/>



              <Label Grid.Column="1"
                      Grid.Row="1"
                       Text="{Binding CUSTOMER_CODE}"
                       TextColor="White"
                       FontSize="18"
                       Opacity="0.6"/>


              <Label Grid.Column="1"
                  Grid.Row="2"
                  Text="{Binding CUSTOMER_MOBILE_NUMBER}"
                   TextColor="White"
                   FontSize="18"
                   Opacity="0.6"/>


              <Label Grid.Column="1"
                  Grid.Row="3"
                  Text="{Binding CUSTOMER_EMAIL_ADDRESS}"
                   TextColor="White"
                   FontSize="18"
                   Opacity="0.6"/>


            </Grid>
          </ViewCell>
        </DataTemplate>
      </ListView.ItemTemplate>

    </ListView>
</StackLayout>


</ContentPage>

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<Customer[]>(json);

            foreach (Customer c in customers)
                viewModel.CustomerList.Add(c);
        }

        async Task<string> 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<Customer> _customerList; // keep all customers
        private ObservableCollection<Customer> _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<Customer> CustomerList
        {
            get
            {
                return _customerList;
            }
            set
            {
                _customerList = value;
                OnPropertyChanged();
            }
        }

        public CustomerVM()
        {
            CustomerList = new ObservableCollection<Customer>();
        }



        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            var handler = PropertyChanged;
            if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
        }

    }
}

但这一次,我需要在饼图中进行。

我真的不知道该怎么做。但我认为我从上面的 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<Sales> _salesList; // keep all customers


        public ObservableCollection<Sales> SalesPerProductModel
        {
            get
            {
                return _salesList;
            }
            set
            {
                _salesList = value;
                OnPropertyChanged();
            }
        }

        public SalesPerProductViewModel()
        {

            SalesPerProductModel = new ObservableCollection<Sales>();


        }




        public event PropertyChangedEventHandler PropertyChanged;

        protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }



    }
}

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

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:oxy="clr-namespace:OxyPlot.Xamarin.Forms;assembly=OxyPlot.Xamarin.Forms"
             xmlns:ViewModels="clr-namespace:XamarinFormsDemo.ViewModels;assembly=XamarinFormsDemo"
             x:Class="XamarinFormsDemo.Views.SalesPerProductPage"
             BackgroundImage="bg3.jpg"
             Title="Sales Per Product">


  <ContentPage.BindingContext>
    <ViewModels:SalesPerProductViewModel/>
  </ContentPage.BindingContext>



  <Label Text="TOTAL SALES LABEL HERE!"
       TextColor="#24e97d"/>

    <oxy:PlotView Model="{Binding SalesPerProductModel}" />
</ContentPage>

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<Sales[]>(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<string> 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:

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:oxy="clr-namespace:OxyPlot.Xamarin.Forms;assembly=OxyPlot.Xamarin.Forms"
             xmlns:local="clr-namespace:App1"
             x:Class="App1.SalesPerProductPage">

  <ContentPage.Content>
      <oxy:PlotView Model="{Binding SalesPerProductModel}"></oxy:PlotView>
  </ContentPage.Content>

</ContentPage>

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<Sales[]>(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<string> 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()
    {
    }
}

enter image description here

关于c# - Xamarin.Forms:如何从 Web API 数据填充饼图?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38889999/

相关文章:

c# - 我想在关闭我的 UWP 应用程序之前存储一个 int 值

asp.net-mvc-4 - 使用 MVC 4 RC 实现 Web API 的 ValidatingAntiForgeryToken 属性时出现问题

c# - 配置 intellitest 以仅使用 Visual Studio 2015 RC 中的一个测试项目

listview - FlowListView 无法通过简单示例正常工作

c# - 访问路径被拒绝,在 Ubuntu 上运行 Asp.net core 2.0

c# - 了解 LINQ to SQL 中的 .AsEnumerable()

c# - MSDeploy:来自命令行的 "Leave extra files on destination"?

asp.net-web-api - ASP.NET Web API中的回调方法

c# - 使用 Web API 反序列化为具有抽象属性的类

android - 在 Xamarin.Forms 中复制下拉 ToolbarItem "More"