Home > Enterprise >  Xamarin forms how to take the property from a observablecollection and put it into a CarouselView
Xamarin forms how to take the property from a observablecollection and put it into a CarouselView

Time:01-05

I want to create a level selector using CarouselView displaying 6 levels per each screen scrolls. I have create a Model for a LevelCard meaning each one of the cards have their own value, I've done this because each level has a number of stars you've scored to be displayed meaning I need to have an instance of each card to update the stars for each level(card).

Ingore PopulateCardInformation method that method isn't finished nor it will be like this, I just made it for quick testing but nothing seems to work.

If you look at the last image you can see while debugging I can select the needed card but I can never actually pull the property to display as text. I've searched every where and this is what I've tried to write in Path=card1[Game], Path=Game[card1], Path=card1.Game, Path=Game.card1 every time I add anything to do with a property name it actually looking in my Model.NameOfProperty... its looking for another model called Game...

public class LevelCard
{
    public int Game { get; set; }
    public int Score { get; set; }
    public bool IsCompleted { get; set; }
}
public class LevelSelectorPopUpModel : BaseViewModel
{
    ObservableCollection<LevelCard> cards = new ObservableCollection<LevelCard>();
    public ObservableCollection<LevelCard> Cards
    {
        get => cards;
    }

    int game = 1;
    int totalGames;

    public LevelSelectorPopUpModel()
    {
        Initialize();
    }

    async void Initialize()
    {
        totalGames = await LevelReader.GetTotalGames();
        InitializeWidthHeightProperties();
        InitializeCards();
    }

    void InitializeCards()
    {
        LevelCard card1 = new LevelCard();
        LevelCard card2 = new LevelCard();
        LevelCard card3 = new LevelCard();
        LevelCard card4 = new LevelCard();
        LevelCard card5 = new LevelCard();
        LevelCard card6 = new LevelCard();

        cards.Add(card1);
        cards.Add(card2);
        cards.Add(card3);
        cards.Add(card4);
        cards.Add(card5);
        cards.Add(card6);

        PopulateCardInformation();
    }

    void PopulateCardInformation()
    {
        foreach (var card in cards)
        {
            if (totalGames < game)
                return;
            card.Game = game;
            game  ;
        }
    }
}

XAML

<CarouselView ItemsSource="{Binding Cards}"
                HorizontalScrollBarVisibility="Always"
                WidthRequest="{Binding Width}"
                HeightRequest="600"
                Margin="10, 0, 10, 0"
                BackgroundColor="Red"
                HorizontalOptions="CenterAndExpand"
                VerticalOptions="CenterAndExpand">

    <CarouselView.ItemTemplate>
        <DataTemplate>
            <Grid RowSpacing="50"
                    VerticalOptions="CenterAndExpand">
                <Grid.RowDefinitions>
                    <RowDefinition Height="*" />
                    <RowDefinition Height="*" />
                </Grid.RowDefinitions>

                <StackLayout Orientation="Horizontal"
                                WidthRequest="600"
                                HeightRequest="250"
                                BackgroundColor="Orange"
                                VerticalOptions="CenterAndExpand"
                                HorizontalOptions="CenterAndExpand"
                                Margin="0, 10, 0, 0">
                    <Label Text="{Binding Path=card1, FallbackValue='Error'}"
                            BackgroundColor="Purple"
                            WidthRequest="200"
                            HeightRequest="200" />
                    <Label Text="{Binding Path=card2, FallbackValue='Error'}"
                            BackgroundColor="Purple"
                            WidthRequest="200"
                            HeightRequest="200" />
                    <Label Text="{Binding Path=card3, FallbackValue='Error'}"
                            BackgroundColor="Purple"
                            WidthRequest="200"
                            HeightRequest="200" />
                </StackLayout>

                <StackLayout Orientation="Horizontal"
                                WidthRequest="600"
                                HeightRequest="250"
                                BackgroundColor="Orange"
                                Grid.Row="1"
                                VerticalOptions="CenterAndExpand"
                                HorizontalOptions="CenterAndExpand"
                                Margin="0, 0, 0, 10">
                    <Label BackgroundColor="Purple"
                            WidthRequest="200"
                            HeightRequest="200" />
                    <Label BackgroundColor="Purple"
                            WidthRequest="200"
                            HeightRequest="200" />
                    <Label BackgroundColor="Purple"
                            WidthRequest="200"
                            HeightRequest="200" />
                </StackLayout>
            </Grid>
        </DataTemplate>
    </CarouselView.ItemTemplate>
</CarouselView>     

enter image description here enter image description here

CodePudding user response:

A CarousalView is not the best choice to show what you want. However, you can make it work by understanding how it works. The CarousalView internally stores an item as CurrentItem. Each time you scroll it, it will change its CurrentItem to the next item. That means, the first time you see your CarousalView, its CurrentItem is the first card you added to the Cards collection. When you write {Binding card1} in the ItemTemplate it tries to find a property named card1 inside its CurrentItem, which is a Card and does not have such property. If number 6 is fixed, you create a helper class:

public class LevelCardGroup 
{
    public LevelCard Card1 { get; }
    public LevelCard Card2 { get; }
    public LevelCard Card3 { get; }
    public LevelCard Card4 { get; }
    public LevelCard Card5 { get; }
    public LevelCard Card6 { get; }

    public LevelCardGroup(LevelCard card1, LevelCard card2, LevelCard card3,
        LevelCard card4, LevelCard card5, LevelCard card6)
    {
        Card1 = card1;
        Card2 = card2;
        Card3 = card3;
        Card4 = card4;
        Card5 = card5;
        Card6 = card6;
    }
}

And change your view model to add instances of the helper class inside the Cards collection:

ObservableCollection<LevelCardGroup> cards = new ObservableCollection<LevelCardGroup>();
public ObservableCollection<LevelCardGroup> Cards
{
    get => cards;
}

void InitializeCards()
{
    LevelCard card1 = new LevelCard();
    LevelCard card2 = new LevelCard();
    LevelCard card3 = new LevelCard();
    LevelCard card4 = new LevelCard();
    LevelCard card5 = new LevelCard();
    LevelCard card6 = new LevelCard();

    cards.Add(new LevelCardGroup(card1, card2, card3, card4, card5, card6));

    PopulateCardInformation();
}

You have to change PopulateCardInformation as well. And in your view:

<Label Text="{Binding Path=Card1.Game, FallbackValue='Error'}"
    BackgroundColor="Purple"
    WidthRequest="200"
    HeightRequest="200" />

Now the CurrentItem of the CarousalView will be LevelCardGroup which contains a property named Card1 and its value has a property named Game.

  • Related