File: IndicatorView\IndicatorStackLayout.cs
Web Access
Project: src\src\Controls\src\Core\Controls.Core.csproj (Microsoft.Maui.Controls)
using System.ComponentModel;
using Microsoft.Maui.Controls.Shapes;
using Microsoft.Maui.Graphics;
 
namespace Microsoft.Maui.Controls
{
	internal class IndicatorStackLayout : StackLayout
	{
		readonly IndicatorView _indicatorView;
		public IndicatorStackLayout(IndicatorView indicatorView)
		{
			_indicatorView = indicatorView;
			Orientation = StackOrientation.Horizontal;
			_indicatorView.PropertyChanged += IndicatorViewPropertyChanged;
		}
 
		protected override void OnChildAdded(Element child)
		{
			base.OnChildAdded(child);
 
			if (child is View view)
			{
				var tapGestureRecognizer = new TapGestureRecognizer
				{
					Command = new Command(sender => _indicatorView.Position = Children.IndexOf(sender)),
					CommandParameter = view
				};
				view.GestureRecognizers.Add(tapGestureRecognizer);
			}
		}
 
		void IndicatorViewPropertyChanged(object? sender, PropertyChangedEventArgs e)
		{
			if (e.PropertyName == IndicatorView.IndicatorsShapeProperty.PropertyName
				|| e.PropertyName == IndicatorView.IndicatorTemplateProperty.PropertyName)
			{
				ResetIndicators();
			}
			if (e.PropertyName == IndicatorView.MaximumVisibleProperty.PropertyName
				|| e.PropertyName == IndicatorView.PositionProperty.PropertyName
				|| e.PropertyName == IndicatorView.HideSingleProperty.PropertyName
				|| e.PropertyName == IndicatorView.IndicatorColorProperty.PropertyName
				|| e.PropertyName == IndicatorView.SelectedIndicatorColorProperty.PropertyName
				|| e.PropertyName == IndicatorView.IndicatorSizeProperty.PropertyName)
			{
				ResetIndicatorStyles();
			}
		}
 
		void ResetIndicatorStyles()
		{
			try
			{
				BatchBegin();
				ResetIndicatorStylesNonBatch();
			}
			finally
			{
				BatchCommit();
			}
		}
 
		internal void ResetIndicators()
		{
			try
			{
				BatchBegin();
				BindIndicatorItems();
			}
			finally
			{
				ResetIndicatorStylesNonBatch();
				BatchCommit();
			}
		}
 
		internal void ResetIndicatorCount(int oldCount)
		{
			try
			{
				BatchBegin();
				if (oldCount < 0)
				{
					oldCount = 0;
				}
 
				if (oldCount > _indicatorView.Count)
				{
					return;
				}
 
				BindIndicatorItems();
			}
			finally
			{
				ResetIndicatorStylesNonBatch();
				BatchCommit();
			}
		}
 
		void ResetIndicatorStylesNonBatch()
		{
			var indicatorCount = _indicatorView.Count;
			var childrenCount = Children.Count;
 
			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)
				{
					return;
				}
 
				visualElement.BackgroundColor = isSelected
					? GetColorOrDefault(_indicatorView.SelectedIndicatorColor, Colors.Gray)
					: GetColorOrDefault(_indicatorView.IndicatorColor, Colors.Silver);
 
 
				VisualStateManager.GoToState(visualElement, isSelected
					? VisualStateManager.CommonStates.Selected
					: VisualStateManager.CommonStates.Normal);
 
			}
 
			IsVisible = indicatorCount > 1 || !_indicatorView.HideSingle;
		}
 
		Color GetColorOrDefault(Color? color, Color defaultColor) => color ?? defaultColor;
 
		void BindIndicatorItems()
		{
			var indicatorSize = _indicatorView.IndicatorSize > 0 ? _indicatorView.IndicatorSize : 10;
			var indicatorTemplate = _indicatorView.IndicatorTemplate ??= new DataTemplate(() => new Border
			{
				Padding = 0,
				VerticalOptions = LayoutOptions.Center,
				HorizontalOptions = LayoutOptions.Center,
				WidthRequest = indicatorSize,
				HeightRequest = indicatorSize,
				StrokeShape = new RoundRectangle()
				{
					CornerRadius = _indicatorView.IndicatorsShape == IndicatorShape.Circle
						? (float)indicatorSize / 2
						: 0,
					Stroke = Colors.Transparent
				}
			});
 
			BindableLayout.SetItemsSource(this, _indicatorView.ItemsSource);
			BindableLayout.SetItemTemplate(this, indicatorTemplate);
		}
 
		public void Remove()
		{
			_indicatorView.PropertyChanged -= IndicatorViewPropertyChanged;
		}
	}
}