I defined a CarouselView with the use of left and right arrows.

The problem is that in my views, there are graphic elements which take quite a long time to load.

When I press the scroll arrows several times in a row and quickly, I get the following error:

MAUI Java.Lang.IllegalStateException: 'The specified child already has a parent. You must call removeView() on the child's parent first.'

I think it's two things. Or a bug related to SkiaSharp and SKCanvasView (these elements are in the carouselview views). Either because I scroll through the views even though the scrolling is not finished.

Here is an example of my code.


using MathomicsEnseignantMaui.Controls;
using MathomicsEnseignantMaui.Listener;
using MathomicsEnseignantMaui.Models;
using MathomicsEnseignantMaui.ViewModels;
using MathomicsEnseignantMaui.Views.SubViews.PupilCarousel;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;

using System.Text;
using System.Threading.Tasks;
using Microsoft.Maui.Controls.Xaml;
using Microsoft.Maui.Controls;
using Microsoft.Maui;
using System.Diagnostics;

namespace MathomicsEnseignantMaui.Views.SubViews
{
    [XamlCompilation(XamlCompilationOptions.Compile)]
    public partial class CompetenceSelector: StackLayout
    {
        public SetCompetenceListener SetCompetenceListener { get; set; } = null;

        public static readonly BindableProperty PupilProperty = BindableProperty.Create(nameof(Pupil), typeof(Pupil), typeof(CompetenceSelector), null);
        public Pupil Pupil
        {
            get { return (Pupil)GetValue(PupilProperty); }
            set
            {
                if(value == null)
                {
                    Console.WriteLine("CarouselCompetencesView", "ONCOMPETENCESELECTOR SET PUPIL IS NULL");
                }
                SetValue(PupilProperty, value);
            }
        }

        public static readonly BindableProperty ClasseProperty = BindableProperty.Create(nameof(Classe), typeof(Classe), typeof(CompetenceSelector), null);
        public Classe Classe
        {
            get { return (Classe)GetValue(ClasseProperty); }
            set
            {
                SetValue(ClasseProperty, value);
            }
        }

        public static readonly BindableProperty CarouselProperty = BindableProperty.Create(nameof(Carousel), typeof(CarouselView), typeof(CompetenceSelector), null, propertyChanged : InitCarouselOnChange);

        public CarouselView Carousel
        {
            get { return (CarouselView)GetValue(CarouselProperty); }
            set { SetValue(CarouselProperty, value); }
        }

        private static void InitCarouselOnChange(BindableObject view, object oldValue, object newValue)
        {
             CompetenceSelector _view = (CompetenceSelector)view;
            _view.Carousel = (CarouselView)newValue;

            if (_view.Carousel != null )
            {
                _view.Carousel.ScrollTo(0);
                _view.IsScrolling = true;
                   
                _view.Carousel.Scrolled += (e, v) => {
                    Console.WriteLine("COMPETENCE SELECTOR -  is SCROLLING END START METHOD - IS DRFAGGED" + _view.Carousel.IsDragging);
                    ObservableCollection<ITitled> entries = (ObservableCollection<ITitled>)_view.Carousel.ItemsSource;
                        int currentIndex = entries.IndexOf((ITitled)_view.Carousel.CurrentItem);
                       _view._selectorAllCompetences.IsChecked = (currentIndex == 0);
//                    _view.Carousel.SetIsDragging(false);

                    Console.WriteLine("COMPETENCE SELECTOR -  is SCROLLING END END METHOD - IS DRFAGGED" + _view.Carousel.IsDragging);

                    _view.IsScrolling = false;
                };
                _view.Carousel.CurrentItemChanged += (e, v) =>
                {
                    Console.WriteLine("COMPETENCE SELECTOR -  CurrentItemChanged END METHOD - IS DRFAGGED" + _view.Carousel.IsDragging);
                    Console.WriteLine("Position: " + _view.Carousel.Position);

                };
//                CurrentItemChanged = "CarouselViewItemChanged"
            }
        }

        private bool IsScrolling = false ;
        public CompetenceSelector()
        {
            InitializeComponent();
  //          BindingContext = this;
        }

        public void NextCompetence(object sender, EventArgs args)
        {

            if ( !Scrolling())
            {
                ObservableCollection<ITitled> entries = (ObservableCollection<ITitled>)Carousel.ItemsSource;
                ITitled currentItem = (ITitled)this.Carousel.CurrentItem;
                int currentIndex = entries.IndexOf((ITitled)this.Carousel.CurrentItem);
                int nextIndex = (currentIndex + 1) % entries.Count();

                ITitled nextItem = entries[nextIndex];

                setPositionCarousel(currentIndex, nextIndex, entries);
                this._selectorAllCompetences.IsChecked = (nextIndex == 0);

                this._selectorAllCompetences.IsEnabled = true;
            }
                      
        }

        public void SetCompetence(String title, bool animate = true)
        {
            ObservableCollection<ITitled> entries = (ObservableCollection<ITitled>)Carousel.ItemsSource;
            foreach(ITitled entry in entries)
            {
                if(entry.Name == title)
                {
                    
                    //                    this.Carousel.ScrollTo(entries.IndexOf(entry), animate);
                    if (animate) { this.Carousel.ScrollTo(entries.IndexOf(entry)); }
                    else {
                        this.Carousel.CurrentItem = entry;
                    }
                    break;
                }
            }
        }

        private void setPositionCarousel(int currentIndex, int nextIndex, ObservableCollection<ITitled> entries)
        {

            IsScrolling = true;
//            this.Carousel.SetIsDragging(true);

            Console.WriteLine("COMPETENCE SELECTOR -  is SCROLLING START  - IS DRFAGGED" + Carousel.IsDragging);
            this.Carousel.ScrollTo(nextIndex);
            Console.WriteLine("COMPETENCE SELECTOR -  is SCROLLING START AFTER SCROLL TO  - IS DRAGGED" + Carousel.IsDragging);

            if (SetCompetenceListener != null)
            {
                SetCompetenceListener.Action(entries[nextIndex]);
            }

        }

        private int GetIndexOfCurrentItem()
        {
            ObservableCollection<ITitled> entries = (ObservableCollection<ITitled>)Carousel.ItemsSource;
            ITitled currentItem = (ITitled)this.Carousel.CurrentItem;

            return entries.IndexOf((ITitled)this.Carousel.CurrentItem);
        }
        public void PreviousCompetence(object sender, EventArgs args)
        {
            if (!Scrolling()) {
                ObservableCollection<ITitled> entries = (ObservableCollection<ITitled>)Carousel.ItemsSource;
                int currentIndex = GetIndexOfCurrentItem();
                int nextIndex = currentIndex - 1 < 0 ? entries.Count() - 1 : currentIndex - 1;
                ITitled nextItem = (ITitled)entries[nextIndex];

                setPositionCarousel(currentIndex, nextIndex, entries);
            
                this._selectorAllCompetences.IsChecked = (nextIndex == 0);            
                this._selectorAllCompetences.IsEnabled = true;
            }

        }
        public void ReturnToAllCompetences()
        {
            if(this.Carousel != null) {
                
                if(GetIndexOfCurrentItem() != 0 && !Scrolling()) { 
                    IsScrolling = true;
                    this.Carousel.ScrollTo(0);
                    if(SetCompetenceListener != null)
                    {
                        SetCompetenceListener.Action(null);
                    }
                }                               
            }
        }

        private bool Scrolling()
        {
            return IsScrolling || Carousel.IsDragging;
        }
    
        void OnCheckBoxCheckedChanged(object sender, CheckedChangedEventArgs e)
        {
            if (e.Value)
            {
                ReturnToAllCompetences();
            }
        }

     
        async void PushModalPage(object sender,EventArgs args)
        {
            var competencesListPage = new TreeCarouselView(this.Classe, this.Pupil);
            await Navigation.PushModalAsync(competencesListPage);
        }
    }
}

As you see, I try to set IsScrolling when I start scrolling and stop it when I call the scrolled event. But it does not work.

Here is the view in which I call this function:

<?xml version="1.0" encoding="utf-8"?>
<StackLayout 
        xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
        xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
        x:Class="MathomicsEnseignantMaui.Views.SubViews.CarouselCompetences.CarouselCompetencesView"    
        HorizontalOptions="FillAndExpand"
        VerticalOptions="FillAndExpand"   
        xmlns:controls="clr-namespace:MathomicsEnseignantMaui.Views.Controls;assembly=MathomicsEnseignantMaui"
        xmlns:microcharts="clr-namespace:Microcharts2;assembly=MathomicsEnseignantMaui"
         xmlns:subviews="clr-namespace:MathomicsEnseignantMaui.Views.SubViews;assembly=MathomicsEnseignantMaui"
        x:Name="MyCarouselCompetence"
        >

    <subviews:TitleView  
        x:Name="_titleView"
        Title="{Binding classe.tag, StringFormat='Progression - {0:F0}', Source={x:Reference MyCarouselCompetence}}"
        HorizontalOptions="CenterAndExpand" Margin="10,0,10,0"
        HeightRequest="70"/>


    <Grid RowDefinitions="5*,1*"
        HorizontalOptions="FillAndExpand"
        VerticalOptions="FillAndExpand">
        
        <CarouselView 
            Grid.Row="0"
            x:Name="_CarouselCompetencesView"
            HorizontalOptions="FillAndExpand"
            VerticalOptions="FillAndExpand"
            Scrolled="OnSwiped"
            IsBounceEnabled="True"
            ItemsSource="{Binding ContentViews, Source={x:Reference MyCarouselCompetence}}"
        >
            <CarouselView.ItemTemplate>
                <DataTemplate >
                    <Grid HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" RowDefinitions="1*,1*" >
                        <ContentView Grid.Row="0" Padding="50,10,50,0" BackgroundColor="{StaticResource backgroundColor}" Margin="0,0,0,5">
                            <ContentView Content="{Binding content}"/>
                        </ContentView>
                        <ContentView Grid.Row="1" Content="{Binding curveContent}"  Margin="0,0,0,5"/>
                    </Grid>
                </DataTemplate>
            </CarouselView.ItemTemplate>
        </CarouselView>
        

        <subviews:CompetenceSelector
            x:Name="_competenceSelector"
            Carousel="{Binding ., Source={x:Reference _CarouselCompetencesView}}"
            Grid.Row="1" BackgroundColor="{StaticResource backgroundColor}"
            Classe="{Binding classe, Source={x:Reference MyCarouselCompetence}, Mode=TwoWay}"
            />
  
    </Grid>
</StackLayout>

A view with SKCanvasView is called here in the datatemplate

ContentView Content="{Binding content}"/>

I want scrolling to happen without crashing the application. Even when I scroll very quickly.

Thank you for your help.

0

There are 0 best solutions below