0

I am trying to figure this out for about 3 days now.

TL;DR: How can I put several OxyPlots (of different kinds) in a scrollable ScrollPage (on a ContentPage)? Can someone explain me in which relationship which element in XAML and the CS Codebase is?


The question seems simple, but I struggle to get this going. Every page shows the same examples or is not specific enough for my problem, only scattered problems. Basically, I want to do this:

enter image description here

So now I encounter a few problems like the graph fills the whole site, the graph doesnt display, I cant use MultiView for some reason, etc. etc.

Most of the tutorials rely on setting the whole content of the page as the chart. Some others can bypass that but only with cryptic XAML or XAML that wont work (MultiView, I use a ScrollPage instead of a ContentPage, so I cant set the <ContentPage.BindingContext/> attribute, or overrides void OnAppearing(). Also setting the BindingContext via Code in CS wont help, because it seems that that only applies to single- chart- pages.

(I initialized the renderer. I already had charts being shown in my app.)

So this is how I understand it:

<?xml version="1.0" encoding="UTF-8"?>
<ScrollView xmlns="http://xamarin.com/schemas/2014/forms" 
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:d="http://xamarin.com/schemas/2014/forms/design"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             xmlns:oxy="clr-namespace:OxyPlot.Xamarin.Forms;assembly=OxyPlot.Xamarin.Forms"
             mc:Ignorable="d"
             x:Class="PieCharter.Test">
    <ScrollView.Content>
        <oxy:PlotView Model="{Binding Model}" IsVisible="True"/>
    </ScrollView.Content>
</ScrollView>

I can set one (or more) of those charts here in XAML, and they should appear as the page content with this codebase:

using System;
using System.Text;

using Xamarin.Forms;
using Xamarin.Forms.Xaml;

using OxyPlot;
using OxyPlot.Series;
using OxyPlot.Xamarin;
using OxyPlot.Xamarin.Forms;

namespace PieCharter
{
    [XamlCompilation(XamlCompilationOptions.Compile)]
    public partial class Test : ScrollView
    {

        public Test()
        {
            InitializeComponent();

            Content = new PlotView
            {
                Model = CreatePieChart()
            };
        }

        private PlotModel CreatePieChart()
        {
            var model = new PlotModel { Title = "PieChart" };

            var ps = new PieSeries
            {
                StrokeThickness = 0.25,
                InsideLabelPosition = 0.25,
                AngleSpan = 360,
                StartAngle = 0
            };

            ps.Slices.Add(new PieSlice("Slice 1, 50");
            ps.Slices.Add(new PieSlice("Slice 2, 50");
            ps.Slices.Add(new PieSlice("Slice 3, 50");

            model.Series.Add(ps);

            return model;
        }
    }
}

But this gives me problems because it sets the whole page to the chart and I cant compartmentalize them into e.g. a Grid view (also while using Layout container and multiple PlotViews it didnt help).

Why cant I just create a few private PlotView PiePlotView, give them the Model = CreateXChart() as argument and set the content of my page in the XAML files as the PlotViews?

It really confuses me, and the documentation is not really helpful, unfortunately.

What does the Model="{Binding Model}" actually mean? Is Model a member of PlotView? (It should be, but I've seen people using other variables.) And if so, how would my XAML know which Model to use when putting multiple OxyPlots into one file? I suppose it has to do with the BindingContext/<ContentPage.BindingContext/> or something.

Can someone please explain it to me in a bit more detail how to accomplish this, and if you dont provide a solution, please help me at least understanding what is going on at all. Its irritating and I honestly somehow think that XAML seems to be quite the inelegant and messy solution (at least it looks to me like that).

I have knowledge of the basics of XAML, I dont know nothing. But its just the interaction between these two parts I cant wrap my head around...


What I already tried (and many more, but probably got various things wrong):

1, 2, 3, 4, 5, ...

Vandrey
  • 531
  • 1
  • 8
  • 23
  • use a Layout container - StackLayout, Grid, etc - to contain multiple views in a page (or ScrollView) – Jason Mar 31 '20 at 20:00
  • I should have mentioned that I used that already. I'll do that right away – Vandrey Mar 31 '20 at 20:01
  • What does the Model="{Binding Model}" actually mean? => Do you understand Binding and BindingContext? Binding context of a View is by default set to the BindingContext of it's Parent. Here the BindingContext of ScrollView is the BindingContext of the View where you are going to add the ScrollView, which I guess is a Page???? – Nikhileshwar Mar 31 '20 at 20:07
  • Well thats the Problem, I know I can use containers to host multiple items on a page. But with plots it doesn't seem to be that easy. It just wouldn't work. My question is, as you correctly understood: How to post multiple plots on a single page. – Vandrey Mar 31 '20 at 20:07
  • `Model="{Binding Model}"` = this sets the `Model` property of the chart to the `Model` property of the `BindingContext`. BindingContext is inherited, so you can set it once for a Page and everything on the page will inherit, or you can assign per-view, or even intermix the approaches – Jason Mar 31 '20 at 20:10
  • Yeah I thought I understand it. But I dont seem to catch what the displayed part of the plot actually is: The plot view or the plot model? – Vandrey Mar 31 '20 at 20:10
  • 1
    the model is the data that drives the chart, generally. You could have a line graph and a bar chart, for instance, that both displayed the same data/model but in different ways. – Jason Mar 31 '20 at 20:14
  • You are setting the Content again the code behind, I don't find that necessary and also Add your ViewModel here it would please us. – Nikhileshwar Mar 31 '20 at 20:14
  • Thank you for your answer until now! I will rethink some things. Unfortunately, I dont have much time now, so I'll answer as soon as I can. – Vandrey Mar 31 '20 at 20:15
  • I think I had come across this issue before. Probably dumb question but have you tried setting `HeightRequest` explicitly? – Morse Mar 31 '20 at 21:20
  • @Nikhileshwar Umm, my ViewModel? Its the standard ViewModel. You mean I should derive my own ViewModel for my Charts? – Vandrey Apr 01 '20 at 17:23
  • @Prateek I havent! Ill try to get this going and also will try out your solution you've provided. Thank you! I hope I can solve it like that. – Vandrey Apr 01 '20 at 17:24
  • @Sunburst275, I asked for the class which you are setting as BindingContext to the Page. Check with Prateek's answer. Do you still need any suggestions on this? – Nikhileshwar Apr 01 '20 at 18:39
  • @Nikhileshwar I set an instance of my `PlotView` as binding context. And yes I still have trouble understanding whats going on, honestly... – Vandrey Apr 02 '20 at 09:37
  • https://chat.stackoverflow.com/rooms/210795/room-for-nikhileshwar-and-sunburst275 could you please connect to this chat box? The conversation is getting to long here – Nikhileshwar Apr 02 '20 at 10:34

1 Answers1

0

ScrollView can have only one children, so you can add a children which in turn can have multiple children like StackLayout or Grid

Model refers to current model for the graph/chart, you have to set it , if you are using Binding the page needs to have same BindingContext mapped to the viewmodel having property with same name, and Viewmodel should implement INotifyPropertyChanged

In code behind of content page

public TestPage()
{
    BindingContext = new TestViewModel();
}

TestViewModel

public class TestViewModel : INotifyPropertyChanged 
{
    public TestViewModel () 
    {
        //initialize Model 1..4
    }

    public Model Model1 
    {
        get => _Model1;

        set 
        {
            _Model1 = value;
            //set value
            NotifyPropertyChanged (); // implemented method for INotifyPropertyChanged
        }
    }

}
<?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:d="http://xamarin.com/schemas/2014/forms/design" 
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:oxy="clr-namespace:OxyPlot.Xamarin.Forms;assembly=OxyPlot.Xamarin.Forms" 
             mc:Ignorable="d" 
             x:Class="PieCharter.Test">
    <ContentPage.Content>
        <ScrollView>
            <StackLayout>
                <Label Text="Some label1 " />
                <Label Text="And some stuff" />
                <PlotView x:Name="plotview1" 
                    Model="{Binding Model1}" 
                    IsVisible="True" 
                    HeightRequest="300" />
                <PlotView x:Name="plotview2" 
                    Model="{Binding Model2}" 
                    IsVisible="True" 
                    HeightRequest="300" />
                <PlotView x:Name="plotview3" 
                    Model="{Binding Model3}" 
                    IsVisible="True" 
                    HeightRequest="300" />
                <PlotView x:Name="plotview4" 
                    Model="{Binding Model4}" 
                    IsVisible="True" 
                    HeightRequest="300" />
            </StackLayout>
        </ScrollView>
    </ContentPage.Content>
</ContentPage>

Morse
  • 8,258
  • 7
  • 39
  • 64
  • So what you are saying is that I have to derive my own PlotView? And how can I set multiple Models in one PlotView? Its only one property, isnt it? – Vandrey Apr 01 '20 at 17:26
  • I think you have got it confused, PlotView is a single view not collection of views. You can use multiple PlotViews and set Models for each of them separately.. – Morse Apr 01 '20 at 17:39
  • So in the comment `//initialize Model 1..4` you mean I should use 4 different PlotViews and initialize them accordingly in my constructor? – Vandrey Apr 01 '20 at 17:41
  • yes.the UI has 4 plotviews and you will have 4 different models .So 1 contentpage having multiple plotviews – Morse Apr 01 '20 at 17:44
  • Aaah okay now it starts to become clearer. I will try it once I have time for that. Thank you! – Vandrey Apr 01 '20 at 17:47
  • So what I dont get now is, you set your `BindingContext` on your page only once (`BindingContext = new TestViewModel();`). But it has to be four different models which all have a different `PlotView` and thus the binding context differs for every model (because they are all contained inside another `PlotView`), right? Or do I have four different `PlotView`s inside the `public class TestViewModel` and set the `BindingContext` to that class? So my `public class TestViewModel` basically has four `PlotVIew`s? – Vandrey Apr 02 '20 at 09:21
  • And from which namespace is `INotifyPropertyChanged `? – Vandrey Apr 02 '20 at 09:24