Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 16 additions & 5 deletions src/Controls/src/Core/IndicatorView/IndicatorStackLayout.cs
Original file line number Diff line number Diff line change
Expand Up @@ -98,19 +98,30 @@ internal void ResetIndicatorCount(int oldCount)
}
}

protected override void OnInsert(int index, IView view)
{
base.OnInsert(index, view);
ResetIndicatorStylesNonBatch();
}

protected override void OnRemove(int index, IView view)
{
base.OnRemove(index, view);
ResetIndicatorStylesNonBatch();
}

void ResetIndicatorStylesNonBatch()
{
var indicatorCount = _indicatorView.Count;
var childrenCount = Children.Count;
var maxVisible = _indicatorView.MaximumVisible;
var position = _indicatorView.Position;
var selectedIndex = position >= maxVisible ? maxVisible - 1 : position;

for (int index = 0; index < childrenCount; index++)
{
var maxVisible = _indicatorView.MaximumVisible;
var position = _indicatorView.Position;
var selectedIndex = position >= maxVisible ? maxVisible - 1 : position;
bool isSelected = index == selectedIndex;
var visualElement = Children[index] as VisualElement;
if (visualElement is null)
if (Children[index] is not VisualElement visualElement)
{
return;
}
Expand Down
111 changes: 111 additions & 0 deletions src/Controls/tests/TestCases.HostApp/Issues/Issues25598.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Maui.Controls.Sample.Issues.Issue25598">
<VerticalStackLayout
Padding="30,0"
Spacing="25">
<Button
AutomationId="AddItemButton"
Margin="0,20,0,0"
Command="{Binding AddRandomItemCommand}"
Text="Add Random Item"/>

<Button
AutomationId="RemoveItemButton"
Command="{Binding RemoveCurrentItemCommand}"
CommandParameter="{Binding Source={x:Reference carouselView}, Path=Position}"
Text="Remove Current Item"/>
<Grid
x:Name="cvGrid"
Margin="5,0"
RowDefinitions="Auto,50,Auto"
BackgroundColor="Transparent"
HorizontalOptions="FillAndExpand">
<Label
Grid.Row="0"
FontSize="24"
Text="CarouselView + IndicatorView using DataTemplate!"/>
<CarouselView
x:Name="carouselView"
Grid.Row="1"
HorizontalOptions="FillAndExpand"
IndicatorView="indicatorView"
IsScrollAnimated="True"
ItemsSource="{Binding Items}"
ItemsUpdatingScrollMode="KeepScrollOffset"
VerticalOptions="EndAndExpand"
VerticalScrollBarVisibility="Default">
<CarouselView.ItemTemplate>
<DataTemplate>
<Label
FontSize="18"
HorizontalOptions="Center"
Text="{Binding .}"
VerticalOptions="CenterAndExpand"/>
</DataTemplate>
</CarouselView.ItemTemplate>
</CarouselView>

<IndicatorView
x:Name="indicatorView"
Grid.Row="2"
HorizontalOptions="Center"
IndicatorColor="White"
SelectedIndicatorColor="#2040a0">
<IndicatorView.IndicatorTemplate>
<DataTemplate>
<Border
BackgroundColor="Transparent"
HeightRequest="20"
Stroke="Black"
WidthRequest="20">
<Border.StrokeShape>
<RoundRectangle CornerRadius="5"/>
</Border.StrokeShape>
</Border>
</DataTemplate>
</IndicatorView.IndicatorTemplate>
</IndicatorView>
</Grid>
<Grid
x:Name="cvGrid2"
Margin="5,0"
RowDefinitions="Auto,50,Auto"
BackgroundColor="Transparent"
HorizontalOptions="FillAndExpand">
<Label
Grid.Row="0"
FontSize="24"
Text="CarouselView + IndicatorView NOT USING DataTemplate!"/>
<CarouselView
x:Name="carouselView2"
Grid.Row="1"
HorizontalOptions="FillAndExpand"
IndicatorView="indicatorView2"
IsScrollAnimated="True"
ItemsSource="{Binding Items}"
ItemsUpdatingScrollMode="KeepScrollOffset"
VerticalOptions="EndAndExpand"
VerticalScrollBarVisibility="Default">
<CarouselView.ItemTemplate>
<DataTemplate>
<Label
FontSize="18"
HorizontalOptions="Center"
Text="{Binding .}"
VerticalOptions="CenterAndExpand"/>
</DataTemplate>
</CarouselView.ItemTemplate>
</CarouselView>

<IndicatorView
x:Name="indicatorView2"
Grid.Row="2"
HorizontalOptions="Center"
IndicatorColor="Black"
IndicatorsShape="Square"
SelectedIndicatorColor="#2040a0"/>
</Grid>
</VerticalStackLayout>
</ContentPage>
42 changes: 42 additions & 0 deletions src/Controls/tests/TestCases.HostApp/Issues/Issues25598.xaml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
using System.Collections.ObjectModel;

namespace Maui.Controls.Sample.Issues
{
[Issue(IssueTracker.Github, 25598, "IndicatorView with Template won't show when ItemSource reaches 0 Elements", PlatformAffected.Android)]
public partial class Issue25598 : ContentPage
{
public Issue25598()
{
InitializeComponent();
BindingContext = new Issue25598ViewModel();
}
}

public class Issue25598ViewModel : ViewModel
{
int _lastItemIndex = 3;

private ObservableCollection<string> _items = new() { "Item1", "Item2", "Item3" };

public ObservableCollection<string> Items
{
get => _items;
set
{
if (_items != value)
{
_items = value;
OnPropertyChanged(nameof(Items));
}
}
}

public Command AddRandomItemCommand => new(() => Items.Add($"Item{++_lastItemIndex}"));

public Command RemoveCurrentItemCommand => new Command<int>(index =>
{
if (index >= 0 && index < Items.Count)
Items.RemoveAt(index);
});
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
using NUnit.Framework;
using UITest.Appium;
using UITest.Core;

namespace Microsoft.Maui.TestCases.Tests.Issues
{
public class Issue25598 : _IssuesUITest
{
public Issue25598(TestDevice testDevice) : base(testDevice) { }

public override string Issue => "IndicatorView with Template won't show when ItemSource reaches 0 Elements";

[Test]
[Category(UITestCategories.IndicatorView)]
public void IndicatorWithTemplateShouldBeVisible()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Test seems to crash on Windows:

The app was expected to be running still, investigate as possible crash
TearDown : The app was expected to be running still, investigate as possible crash

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think there's something wrong with the UI test with the Carousel view with the data template on Windows. Probably we will have the same crash without any changes. Like we do in this PR: #24776

{
App.WaitForElement("RemoveItemButton");

for (int i = 0; i < 3; i++)
App.Click("RemoveItemButton");

for (int i = 0; i < 3; i++)
App.Click("AddItemButton");

VerifyScreenshot();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Snapshots already available in the latest build.

Example, iOS:
image

}
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
12 changes: 10 additions & 2 deletions src/Core/src/Platform/Android/MauiPageControl.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ public class MauiPageControl : LinearLayout

IIndicatorView? _indicatorView;

bool _isTemplateIndicator;

public MauiPageControl(Context? context) : base(context)
{
}
Expand All @@ -37,6 +39,7 @@ public void ResetIndicators()
{
_pageShape = null;
_currentPageShape = null;
_isTemplateIndicator = false;

if ((_indicatorView as ITemplatedIndicatorView)?.IndicatorsLayoutOverride == null)
UpdateShapes();
Expand All @@ -63,7 +66,7 @@ public void UpdatePosition()

public void UpdateIndicatorCount()
{
if (_indicatorView == null || Context == null)
if (_indicatorView == null || Context == null || _isTemplateIndicator)
return;

var index = GetIndexFromPosition();
Expand Down Expand Up @@ -107,6 +110,7 @@ void UpdateIndicatorTemplate(ILayout? layout)
return;

AView? handler = layout.ToPlatform(_indicatorView.Handler.MauiContext);
_isTemplateIndicator = true;

RemoveAllViews();
AddView(handler);
Expand Down Expand Up @@ -170,7 +174,11 @@ int GetIndexFromPosition()

void RemoveViews(int startAt)
{
for (int i = startAt; i < ChildCount; i++)
if (_isTemplateIndicator)
return;

var count = ChildCount;
for (int i = startAt; i < count; i++)
{
var imageView = GetChildAt(ChildCount - 1);
imageView?.SetOnClickListener(null);
Expand Down