Previous part: Asynchronously Grouping Totals in MAUI [GamesCatalog] - Part 13
Step 1. In MainVM.cs, we’ll create the 3 lists that will hold the images.
private ObservableCollection<UIHorizontalColViewGroupedImage> lastFiveIGDBIdsByUpdatedAtWant = [],
lastFiveIGDBIdsByUpdatedAtPlaying = [], lastFiveIGDBIdsByUpdatedAtPlayed = [];
public ObservableCollection<UIHorizontalColViewGroupedImage> LastFiveIGDBIdsByUpdatedAtWant
{
get => lastFiveIGDBIdsByUpdatedAtWant;
set { if (value != lastFiveIGDBIdsByUpdatedAtWant) SetProperty(ref (lastFiveIGDBIdsByUpdatedAtWant), value); }
}
public ObservableCollection<UIHorizontalColViewGroupedImage> LastFiveIGDBIdsByUpdatedAtPlaying
{
get => lastFiveIGDBIdsByUpdatedAtPlaying;
set { if (value != lastFiveIGDBIdsByUpdatedAtPlaying) SetProperty(ref (lastFiveIGDBIdsByUpdatedAtPlaying), value); }
}
public ObservableCollection<UIHorizontalColViewGroupedImage> LastFiveIGDBIdsByUpdatedAtPlayed
{
get => lastFiveIGDBIdsByUpdatedAtPlayed;
set { if (value != lastFiveIGDBIdsByUpdatedAtPlayed) SetProperty(ref (lastFiveIGDBIdsByUpdatedAtPlayed), value); }
}
Step 1.1. Let’s create the model for the image list.
namespace GamesCatalog.Models
{
public record UIHorizontalColViewGroupedImage(string Url, Thickness Margin);
}
Step 2. We’ll create arrays to manage the modification of the lists.
private string?[] CacheLastFiveIGDBIdsByUpdatedAtWant = [], CacheLastFiveIGDBIdsByUpdatedAtPlaying = [], CacheLastFiveIGDBIdsByUpdatedAtPlayed = [];
Step 3. Let’s create a function that builds the image lists for the screen.
public void BuildColView(List<TotalGroupedByStatus> totalsGroupedByStatus, GameStatus gameStatus, ref ObservableCollection<UIHorizontalColViewGroupedImage> lastFiveIGDBIdsByUpdatedAt, ref string?[] lastFiveIGDBIdsByUpdatedAtCache)
{
TotalGroupedByStatus? totalsGrouped = totalsGroupedByStatus.FirstOrDefault(x => x.Status == gameStatus);
switch (gameStatus)
{
case GameStatus.Want:
QtdWant = totalsGrouped?.Total ?? 0;
break;
case GameStatus.Playing:
QtdPlaying = totalsGrouped?.Total ?? 0;
break;
case GameStatus.Played:
QtdPlayed = totalsGrouped?.Total ?? 0;
break;
}
string?[] _lastFiveIGDBIdsByUpdatedAt = totalsGrouped?.LastFiveIGDBIdsByUpdatedAt ?? [];
if (_lastFiveIGDBIdsByUpdatedAt is null or [])
{
MainVM.ClearColView(ref lastFiveIGDBIdsByUpdatedAt);
lastFiveIGDBIdsByUpdatedAtCache = [];
return;
}
if (!lastFiveIGDBIdsByUpdatedAtCache.SequenceEqual(_lastFiveIGDBIdsByUpdatedAt))
{
MainVM.ClearColView(ref lastFiveIGDBIdsByUpdatedAt);
bool isFisrt = true;
foreach (var item in _lastFiveIGDBIdsByUpdatedAt)
{
if (isFisrt)
{
lastFiveIGDBIdsByUpdatedAt.Add(new UIHorizontalColViewGroupedImage(Path.Combine(GameService.ImagesPath, $"{item}.jpg"), new Thickness(0)));
isFisrt = false;
}
else
lastFiveIGDBIdsByUpdatedAt.Add(new UIHorizontalColViewGroupedImage(Path.Combine(GameService.ImagesPath, $"{item}.jpg"), new Thickness(-45, 0, 0, 0)));
}
}
lastFiveIGDBIdsByUpdatedAtCache = _lastFiveIGDBIdsByUpdatedAt;
}
This function separates the status group, sets the total, and manages the creation of the list, which will be updated if there are any changes in the array of IDs for the last 5 games. The list contains 5 partially overlapping images.
Step 4. Let’s create a function that clears the list.
private static void ClearColView(ref ObservableCollection<UIHorizontalColViewGroupedImage> lastFiveIGDBIdsByUpdatedAt)
{
while (lastFiveIGDBIdsByUpdatedAt.Count > 0)
lastFiveIGDBIdsByUpdatedAt.RemoveAt(lastFiveIGDBIdsByUpdatedAt.Count - 1);
}
Step 5. We’ll modify the SetTotalsGroupedByStatus() function to handle the lists asynchronously.
public async Task SetTotalsGroupedByStatus()
{
await SetTotalsGroupedByStatusSemaphore.WaitAsync();
try
{
List<TotalGroupedByStatus>? totalsGroupedByStatus = await gameService.GetTotalsGroupedByStatus();
if (totalsGroupedByStatus is not null && totalsGroupedByStatus.Count > 0)
{
List<Task> tasks = [
Task.Run(() => BuildColView(totalsGroupedByStatus, GameStatus.Want, ref lastFiveIGDBIdsByUpdatedAtWant, ref CacheLastFiveIGDBIdsByUpdatedAtWant)),
Task.Run(() => BuildColView(totalsGroupedByStatus, GameStatus.Playing, ref lastFiveIGDBIdsByUpdatedAtPlaying, ref CacheLastFiveIGDBIdsByUpdatedAtPlaying)),
Task.Run(() => BuildColView(totalsGroupedByStatus, GameStatus.Played, ref lastFiveIGDBIdsByUpdatedAtPlayed, ref CacheLastFiveIGDBIdsByUpdatedAtPlayed))
];
await Task.WhenAll(tasks);
}
else
{
QtdPlayed = QtdPlaying = QtdWant = 0;
MainVM.ClearColView(ref lastFiveIGDBIdsByUpdatedAtWant);
MainVM.ClearColView(ref lastFiveIGDBIdsByUpdatedAtPlaying);
MainVM.ClearColView(ref lastFiveIGDBIdsByUpdatedAtPlayed);
}
}
catch (Exception ex) { throw ex; }
finally
{
SetTotalsGroupedByStatusSemaphore.Release();
}
}
The three lists will be processed in parallel.
Attached is the full code for the MainVM.cs class.
Step 6. Let’s add a CollectionView with horizontal scrolling to display the images.
![CollectionView]()
Code
<CollectionView
Margin="0"
FlowDirection="RightToLeft"
HorizontalOptions="Start"
ItemsLayout="HorizontalList"
ItemsSource="{Binding LastFiveIGDBIdsByUpdatedAtWant}">
<CollectionView.ItemTemplate>
<DataTemplate x:DataType="model:UIHorizontalColViewGroupedImage">
<AbsoluteLayout
Margin="0"
Padding="0"
IsClippedToBounds="False">
<Image
Margin="{Binding Margin}"
Aspect="Fill"
BackgroundColor="LightGray"
HeightRequest="136"
Source="{Binding Url}"
WidthRequest="100" />
</AbsoluteLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
Step 6.1. In the other two grids, add the CollectionView components for the "to play" and "played" statuses.
![Played]()
Code
<CollectionView
Margin="0"
FlowDirection="RightToLeft"
HorizontalOptions="Start"
ItemsLayout="HorizontalList"
ItemsSource="{Binding LastFiveIGDBIdsByUpdatedAtPlaying}">
<CollectionView.ItemTemplate>
<DataTemplate x:DataType="model:UIHorizontalColViewGroupedImage">
<AbsoluteLayout
Margin="0"
Padding="0"
IsClippedToBounds="False">
<Image
Margin="{Binding Margin}"
Aspect="Fill"
BackgroundColor="LightGray"
HeightRequest="136"
Source="{Binding Url}"
WidthRequest="100" />
</AbsoluteLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
![Code]()
Code
<CollectionView
Margin="0"
FlowDirection="RightToLeft"
HorizontalOptions="Start"
ItemsLayout="HorizontalList"
ItemsSource="{Binding LastFiveIGDBIdsByUpdatedAtPlayed}"
ItemsUpdatingScrollMode="KeepScrollOffset">
<CollectionView.ItemTemplate>
<DataTemplate x:DataType="model:UIHorizontalColViewGroupedImage">
<AbsoluteLayout
Margin="0"
Padding="0"
IsClippedToBounds="False">
<Image
Margin="{Binding Margin}"
Aspect="Fill"
BackgroundColor="LightGray"
HeightRequest="136"
Source="{Binding Url}"
WidthRequest="100" />
</AbsoluteLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
Step 7. Now we have our lists showing the last 5 games for each status on the screen.
![Output]()
In the next step, we will create the listing screen for our games saved in the local database, organized by status.
Code on git: GamesCatalog