Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bar chart inside a ListView control #60

Open
naveeng2228 opened this issue Jun 10, 2017 · 4 comments
Open

Bar chart inside a ListView control #60

naveeng2228 opened this issue Jun 10, 2017 · 4 comments

Comments

@naveeng2228
Copy link

naveeng2228 commented Jun 10, 2017

Steps to reproduce

  1. Add a ListView to your ContentPage.
  2. Create a list of PlotModels to your page for binding to the ListView.
  3. Now use a Template/ ViewCell having PlotView to the ListView.

Platform: Xamarin Forms (Cross-Platform)
.NET version: 4.0

Expected behaviour

While loading the ContentPage, the ListView should load the data based on the PlotModels provided.

Actual behaviour

Everything is running smooth in Android. But the problem is I am getting a error "PlotModel is already in use by some other PlotView control" when I am trying to run it on IPhone.

//My content page
public MyConstructor()
{
	List<MyChart> charts = new List<MyChart>();
	charts.Add(new MyChart { PlotModel = PlotModel1 });
	charts.Add(new MyChart { PlotModel = PlotModel2 });
	charts.Add(new MyChart { PlotModel = PlotModel3 });
	charts.Add(new MyChart { PlotModel = PlotModel4 });
	ListView lvPlots = new ListView(ListViewCachingStrategy.RetainElement)
	{
		ItemsSource = charts,
		ItemTemplate = new DataTemplate(typeof(NewDashboardSubCell)),
		HasUnevenRows = true
	};
	Content = lvPlots;
}

public class MyChart
{
       public MyPlotModel PlotModel { get; set; }
}


//My View Cell

public class NewDashboardSubCell : ViewCell
{
        PlotView plotView;
        public NewDashboardSubCell()
        {
            try
            {
                plotView = new PlotView
                {
                    HorizontalOptions = LayoutOptions.FillAndExpand,
                    VerticalOptions = LayoutOptions.FillAndExpand,
                    IsVisible = true,
                    IsEnabled = true,
                    HeightRequest = App.ScreenHeight - 100,
                    WidthRequest = App.ScreenWidth - 40
                };

                plotView.SetBinding(PlotView.ModelProperty, "PlotModel");

                View = plotView;                
            }
            catch (Exception ex)
            {
            }
	}
}

Code.txt

@flyingxu
Copy link

This is a very common issue of OxyPlot when it's used in MVVM.
In OxyPlot, the view and the model are 1-to-1 mapped, when a second view is trying to bind the same PlotModel, you have the issue of "PlotModel is already in use by some other PlotView control".
On iOS, ListView's cell will be re-created when it is scrolling. In this case, there will be a newly created view trying to bind the same PlotModel, and then you have the issue.
On Android, I guess you will have the same issue too. Try to put your phone from landscape to portrait, see if you have the same issue. In Android, the view will be re-created completely when the orientation is changed.

A quick fix is to break the MVVM design here a little bit. Don't create the model in a separated place but create the model in the view. So whenever a view is re-created by iOS or Android, a new model is also re-created.

You can see issue #17 as well.

@fschwiet
Copy link

iOS had a recent regression where ListViews on iOS were instantiating views for listview elements too much, this may help you: https://bugzilla.xamarin.com/show_bug.cgi?id=56896

Note that the ListView implementation may still instantiate a view multiple times if it needs to estimate the height. But once the issue is fixed (or if you use an earlier version of forms) you should be able to suppress these extra view creations by setting RowHeight on the ListView. See the PR in the bugzilla issue for notes about how that works.

@fschwiet
Copy link

FWIW now I'm butting into the same issue when using OxyPlot in a carouselview (https://github.com/alexrainman/CarouselView).

@LakMoore
Copy link

LakMoore commented Aug 13, 2018

As @flyingxu said, you need to create a new PlotModel every time a new PlotView is used. Easiest way to achieve that is to construct the PlotModel within the same constructor as your PlotView. When using this within a CarouselView, ensure that you use a DataTemplate and not a direct reference to the View. The DataTemplate should be constructed to ensure that a new version is created every time (i.e. on swipe and rotate)

    var myCarousel = new CarouselViewControl();
    myCarousel.ItemsSource = new List<DataTemplate>()
    {
        new DataTemplate(() => { return pairList; } ),  //this view can be cached/re-used
        new DataTemplate(() => { return singlePair; }), //this view can be cached/re-used
        new DataTemplate(() => { 
            tickChart = new Views.TickChart();          //need a new one every time!
            return tickChart; 
        })   
    };
    myCarousel.PositionSelected += OnPositionSelected;
    Content = myCarousel;

@objorke objorke changed the title OxyPlot Bar Chart inside a listview control for Xamarin.Forms Bar chart inside a ListView control Oct 20, 2019
@objorke objorke added this to the v2.0 milestone Nov 28, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants