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>
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
.