Search code examples
c#xamarinxamarin.formsoxyplot

Xamarin.Forms: Error in creating a Chart using OxyPlot


Good Day Everyone. I'm creating a Xamarin.Forms (Portable) Application and I want to create a Chart using OxyPlot. I have tried this code but it has an error that points to my LoadApplication(new App()); MainActivity.cs in my Xamarin.Android part stating that

"System.NullReferenceException: Object Reference not set to an Instance of an Object"

What do you think is the reason behind this?

These are some of the codes I have:

SalesPage.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.SalesPage"
         xmlns:oxy="clr-namespace:OxyPlot.XamarinForms;assembly=OxyPlot.XamarinForms"
         BackgroundImage="bg3.jpg"
         Title="Sales Page">

 <StackLayout>
   <oxy:PlotView Model="{Binding OxyPlotModel}" VerticalOptions="Center" HorizontalOptions="Center" />
</StackLayout>

</ContentPage>

SalesPage.xaml

using OxyPlot;
using OxyPlot.Axes;
using OxyPlot.Series;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;   
using Xamarin.Forms;

namespace XamarinFormsDemo.Views
{
    public partial class SalesPage 
    {


    public SalesPage()
    {
        InitializeComponent();
        var plotModel = new PlotModel { Title = "OxyPlot Demo" };

        plotModel.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom });
        plotModel.Axes.Add(new LinearAxis { Position = AxisPosition.Left, Maximum = 10, Minimum = 0 });

        var series1 = new LineSeries
        {
            MarkerType = OxyPlot.MarkerType.Circle,
            MarkerSize = 4,
            MarkerStroke = OxyPlot.OxyColors.White
        };

        series1.Points.Add(new DataPoint(0.0, 6.0));
        series1.Points.Add(new DataPoint(1.4, 2.1));
        series1.Points.Add(new DataPoint(2.0, 4.2));
        series1.Points.Add(new DataPoint(3.3, 2.3));
        series1.Points.Add(new DataPoint(4.7, 7.4));
        series1.Points.Add(new DataPoint(6.0, 6.2));
        series1.Points.Add(new DataPoint(8.9, 8.9));

        plotModel.Series.Add(series1);
        }
    }
}

MainActivity.cs

using System;
using Android.App;
using Android.Content.PM;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Android.OS;



using ImageCircle.Forms.Plugin.Droid;

namespace XamarinFormsDemo.Droid
{
    [Activity(Label = "XamarinFormsDemo", Icon = "@drawable/recordsicon",     MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize |     ConfigChanges.Orientation)]
    public class MainActivity :     global::Xamarin.Forms.Platform.Android.FormsApplicationActivity
    {
        protected override void OnCreate(Bundle bundle)
        {
        base.OnCreate(bundle);
        global::Xamarin.Forms.Forms.Init(this, bundle);
        LoadApplication(new App());
        OxyPlot.Xamarin.Forms.Platform.Android.PlotViewRenderer.Init();
       ImageCircleRenderer.Init();
        }
    }
}

Solution

  • You don't set the DataContext for the page anywhere. At least not in the code that you are showing. Hence, the binding to the OxyPlotModel property, which also doesn't seem to exist, will not work.

    If you want a quick and dirty fix just to see the model you have made in your page, then simply assign it to the PlotView like so:

    1. Add a name attribute to your plotview. x:Name="Graph"
    2. Simply assign the created PlotModel to the Model property of Graph: Graph.Model = plotModel.

    However, you might need to do that in an OnAppearing override, so your code might need to be moved down in that method like:

    public override void OnAppearing()
    {
        var plotModel = new PlotModel { Title = "OxyPlot Demo" };
    
        plotModel.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom });
        plotModel.Axes.Add(new LinearAxis { Position = AxisPosition.Left, Maximum = 10, Minimum = 0 });
    
        var series1 = new LineSeries
        {
            MarkerType = OxyPlot.MarkerType.Circle,
            MarkerSize = 4,
            MarkerStroke = OxyPlot.OxyColors.White
        };
    
        series1.Points.Add(new DataPoint(0.0, 6.0));
        series1.Points.Add(new DataPoint(1.4, 2.1));
        series1.Points.Add(new DataPoint(2.0, 4.2));
        series1.Points.Add(new DataPoint(3.3, 2.3));
        series1.Points.Add(new DataPoint(4.7, 7.4));
        series1.Points.Add(new DataPoint(6.0, 6.2));
        series1.Points.Add(new DataPoint(8.9, 8.9));
    
        plotModel.Series.Add(series1);
        Graph.Model = plotModel;
    }
    

    A better way to do this is to utilize the MVVM pattern, by creating a ViewModel like so:

    public class SalesViewModel : INotifyPropertyChanged
    {
        private PlotModel _plotModel;
    
        public PlotModel PlotModel
        {
            get { return _plotModel; }
            set {
                _plotModel = value;
                RaisePropertyChanged();
            }
        }
    
        // other methods here that create your model
    
        public event PropertyChangedEventHandler PropertyChanged;
    
        private void RaisePropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null)
                handler (this, new PropertyChangedEventArgs (propertyName));
        }
    }
    

    Then you can instantiate your ViewModel somewhere, probably in OnAppearing() and set it as BindingContext:

    public override void OnAppearing()
    {
        var viewModel = new SalesViewModel();
        this.BindingContext = viewModel;
    }
    

    Then you can use that binding you created in your Page:

    <?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.SalesPage"
        xmlns:oxy="clr-namespace:OxyPlot.XamarinForms;assembly=OxyPlot.XamarinForms"
        BackgroundImage="bg3.jpg"
        Title="Sales Page">
    
        <StackLayout>
            <oxy:PlotView Model="{Binding PlotModel}" VerticalOptions="Center" HorizontalOptions="Center" />
        </StackLayout>
    </ContentPage>
    

    Remember to call RaisePropertyChanged() on your PlotModel every time you change it to get it reflected in the View: RaisePropertyChanged("PlotModel");