Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
8ac95e6
[Testing] Feature Matrix UITest Cases for CheckBox Control (#29739)
May 30, 2025
3e69fa8
Don’t call NSAttributedString with HTML from a background thread (#26…
kubaflo May 30, 2025
3437e46
[create-pull-request] automated change (#29760)
github-actions[bot] Jun 1, 2025
f7ac943
[Android] Fixed Button Shadow Color Transparency Not Applied Correctl…
NanthiniMahalingam Jun 2, 2025
5860fe6
ToolbarItem behavior with ImageSource iOS - fix (#28833)
kubaflo Jun 2, 2025
70b6932
Update the comment for the test properties (#27306)
mattleibow Jun 2, 2025
3690bcd
[create-pull-request] automated change (#29792)
github-actions[bot] Jun 3, 2025
26d4fe3
Perf : ButtonContentTypeConverter now using InvariantCulture to parse…
jonathanantoine Jun 5, 2025
c5351a9
Fixed ItemSpacing on CarouselView resizes items [Android] (#29796)
Dhivya-SF4094 Jun 6, 2025
f66aecf
Fix TapCoordinates method in Catalyst (#29775)
jsuarezruiz Jun 6, 2025
7be53bd
[Testing] Feature Matrix UITest Cases for Stepper (#29731)
nivetha-nagalingam Jun 6, 2025
879edfd
[Testing] Feature Matrix UITest Cases for CollectionView ItemsSource …
LogishaSelvarajSF4525 Jun 6, 2025
17de473
[Windows] Fix for Assigning null to the SelectedItem of the Collectio…
SyedAbdulAzeemSF4852 Jun 6, 2025
efba129
[iOS] Fix for Flyout title is not broken over multiple lines when you…
BagavathiPerumal Jun 6, 2025
b02b432
Templated indicator view - improvements (#25642)
kubaflo Jun 6, 2025
add7f71
[iOS] Fix AdaptiveTrigger not working as expected (#20987)
jsuarezruiz Jun 6, 2025
4d0efba
[create-pull-request] automated change (#29875)
github-actions[bot] Jun 7, 2025
1293cb5
[iOS] FormattedText with text color causes stack overflow - fix (#29874)
kubaflo Jun 9, 2025
e5fd074
[iOS] Fix SwipeView programmatic open when background color is set. (…
Shalini-Ashokan Jun 9, 2025
95f3b9a
[Testing] Feature Matrix UITest Cases for RadioButton (#29744)
TamilarasanSF4853 Jun 9, 2025
a37acc9
[Windows] Implemented the Resize and Downsize functions in the W2DIma…
HarishwaranVijayakumar Jun 9, 2025
35e8a01
Fixed Test case failure in PR 25642 - snapshots (#29881)
kubaflo Jun 16, 2025
25e0f80
Fixed Test case failure in PR 26153 - iOS (#29906)
kubaflo Jun 16, 2025
5e9310b
Update Issue25946.xaml (#30025)
Jun 17, 2025
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
2 changes: 1 addition & 1 deletion src/Controls/src/Core/Button/Button.cs
Original file line number Diff line number Diff line change
Expand Up @@ -598,7 +598,7 @@ public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo c
int spacingIndex = spacingFirst ? 0 : (parts.Length == 2 ? 1 : -1);

if (spacingIndex > -1)
spacing = double.Parse(parts[spacingIndex]);
spacing = double.Parse(parts[spacingIndex], CultureInfo.InvariantCulture);

if (positionIndex > -1)
position = (ButtonContentLayout.ImagePosition)Enum.Parse(typeof(ButtonContentLayout.ImagePosition), parts[positionIndex], true);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,17 @@ internal UIContainerCell(string cellId, View view, Shell shell, object context)
var platformView = view.ToPlatform();
ContentView.AddSubview(platformView);
platformView.AccessibilityTraits |= UIAccessibilityTrait.Button;
platformView.TranslatesAutoresizingMaskIntoConstraints = false;

var margin = view.Margin;
var constraints = new NSLayoutConstraint[]
{
platformView.LeadingAnchor.ConstraintEqualTo(ContentView.LeadingAnchor, (nfloat)margin.Left),
platformView.TrailingAnchor.ConstraintEqualTo(ContentView.TrailingAnchor, (nfloat)(-margin.Right)),
platformView.TopAnchor.ConstraintEqualTo(ContentView.TopAnchor, (nfloat)margin.Top),
platformView.BottomAnchor.ConstraintEqualTo(ContentView.BottomAnchor, (nfloat)(-margin.Bottom))
};
NSLayoutConstraint.ActivateConstraints(constraints);

_renderer.PlatformView.ClipsToBounds = true;
ContentView.ClipsToBounds = true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,9 @@ void UpdateIconAndStyle(ToolbarItem item)
}
item.IconImageSource.LoadImage(mauiContext, result =>
{
Image = result?.Value;
Image = item.IconImageSource is not FontImageSource
? result?.Value.ImageWithRenderingMode(UIImageRenderingMode.AlwaysOriginal)
: result?.Value;
Style = UIBarButtonItemStyle.Plain;
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ double GetItemWidth()
if (double.IsInfinity(width))
return width;

itemWidth = (int)(width - Context?.ToPixels(VirtualView.PeekAreaInsets.Left) - Context?.ToPixels(VirtualView.PeekAreaInsets.Right) - Context?.ToPixels(listItemsLayout.ItemSpacing));
itemWidth = (int)(width - Context?.ToPixels(VirtualView.PeekAreaInsets.Left) - Context?.ToPixels(VirtualView.PeekAreaInsets.Right));
}

return itemWidth;
Expand All @@ -112,7 +112,7 @@ double GetItemHeight()
if (double.IsInfinity(height))
return height;

itemHeight = (int)(height - Context?.ToPixels(VirtualView.PeekAreaInsets.Top) - Context?.ToPixels(VirtualView.PeekAreaInsets.Bottom) - Context?.ToPixels(listItemsLayout.ItemSpacing));
itemHeight = (int)(height - Context?.ToPixels(VirtualView.PeekAreaInsets.Top) - Context?.ToPixels(VirtualView.PeekAreaInsets.Bottom));
}

return itemHeight;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ namespace Microsoft.Maui.Controls.Handlers.Items
public partial class SelectableItemsViewHandler<TItemsView> : StructuredItemsViewHandler<TItemsView> where TItemsView : SelectableItemsView
{
bool _ignorePlatformSelectionChange;
bool _ignoreVirtualSelectionChange;

protected override void ConnectHandler(ListViewBase platformView)
{
Expand Down Expand Up @@ -132,6 +133,13 @@ void UpdatePlatformSelection()

void VirtualSelectionChanged(object sender, SelectionChangedEventArgs e)
{
// When the selection changes within the SelectionChanged event, the new selection isn't immediately reflected in the view.
// After the virtual selection is correctly updated, the flag is reset to enable future updates
if (_ignoreVirtualSelectionChange)
{
_ignoreVirtualSelectionChange = false;
return;
}
UpdatePlatformSelection();
}

Expand Down Expand Up @@ -172,10 +180,10 @@ void UpdateVirtualSingleSelection()

if (ItemsView != null)
{
ItemsView.SelectionChanged -= VirtualSelectionChanged;
_ignoreVirtualSelectionChange = true;
ItemsView.SelectedItem = selectedItem;

ItemsView.SelectionChanged += VirtualSelectionChanged;
_ignoreVirtualSelectionChange = false;
}
}

Expand Down
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
14 changes: 6 additions & 8 deletions src/Controls/src/Core/Label/Label.iOS.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,19 +36,17 @@ public static void MapMaxLines(ILabelHandler handler, Label label)
handler.PlatformView?.UpdateMaxLines(label);
}

static void MapFormatting(ILabelHandler handler, Label label)
internal static void MapFormatting(ILabelHandler handler, Label label)
{
// we need to re-apply color and font for HTML labels
if (!label.HasFormattedTextSpans && label.TextType == TextType.Html)
if (IsPlainText(label))
{
LabelHandler.MapFormatting(handler, label);
}
else if (!label.HasFormattedTextSpans && label.TextType == TextType.Html) // we need to re-apply color and font for HTML labels
{
handler.UpdateValue(nameof(ILabel.TextColor));
handler.UpdateValue(nameof(ILabel.Font));
}

if (!IsPlainText(label))
return;

LabelHandler.MapFormatting(handler, label);
}

void RecalculateSpanPositions(Size size)
Expand Down
17 changes: 16 additions & 1 deletion src/Controls/src/Core/Platform/iOS/Extensions/LabelExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,22 @@ public static void UpdateText(this UILabel platformLabel, Label label)
switch (label.TextType)
{
case TextType.Html:
platformLabel.UpdateTextHtml(label);
// NOTE: Setting HTML text this will crash with some sort of consistency error.
// https://github.com/dotnet/maui/issues/25946
// Here we have to dispatch back the the main queue to avoid the crash.
// This is observed with CarouselView 1 but not with 2, so hopefully this
// will be just disappear once we switch.
CoreFoundation.DispatchQueue.MainQueue.DispatchAsync(() =>
{
platformLabel.UpdateTextHtml(label);

if (label.Handler is LabelHandler labelHandler)
Label.MapFormatting(labelHandler, label);

// NOTE: Because we are updating text outside the normal layout
// pass, we need to invalidate the measure for the next pass.
label.InvalidateMeasure();
});
break;

default:
Expand Down
16 changes: 14 additions & 2 deletions src/Controls/tests/DeviceTests/Elements/Label/LabelTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,10 @@ await AttachAndRun(layout, async (handler) =>

label.TextType = TextType.Html;

// We need to delay here because platformLabel.UpdateTextHtml(label) and label.InvalidateMeasure()
// are dispatched asynchronously to the main thread and may not complete immediately.
// https://github.com/dotnet/maui/pull/26153
await Task.Delay(100);
await platformView.AssertDoesNotContainColor(Colors.Red, MauiContext);
});
}
Expand Down Expand Up @@ -517,9 +521,13 @@ public async Task FontStuffAppliesEvenInHtmlMode()
Text = "<p>Test</p>"
};

await InvokeOnMainThreadAsync(() =>
await InvokeOnMainThreadAsync(async () =>
{
var handler = CreateHandler<LabelHandler>(label);
// We need to delay here because platformLabel.UpdateTextHtml(label) and label.InvalidateMeasure()
// are dispatched asynchronously to the main thread and may not complete immediately.
// https://github.com/dotnet/maui/pull/26153
await Task.Delay(100);
AssertEquivalentFont(handler, label.ToFont());
});
}
Expand Down Expand Up @@ -715,9 +723,13 @@ public async Task FontStuffAfterTextTypeIsCorrect()
Text = "<p>Test</p>"
};

await InvokeOnMainThreadAsync(() =>
await InvokeOnMainThreadAsync(async () =>
{
var handler = CreateHandler<LabelHandler>(label);
// We need to delay here because platformLabel.UpdateTextHtml(label) and label.InvalidateMeasure()
// are dispatched asynchronously to the main thread and may not complete immediately.
// https://github.com/dotnet/maui/pull/26153
await Task.Delay(100);
label.FontFamily = "Baskerville";
label.FontSize = 64;
AssertEquivalentFont(handler, label.ToFont());
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@
<MauiFont Include="Resources\Fonts\**" />
<MauiFont Remove="Resources\Fonts\Dokdo-Regular.ttf" />
<EmbeddedResource Include="Resources\Fonts\Dokdo-Regular.ttf" />
<EmbeddedResource Include="Resources\Images\royals.png" />
<MauiAsset Include="Resources\Raw\**" LogicalName="%(RecursiveDir)%(Filename)%(Extension)" />
</ItemGroup>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,17 +68,20 @@ public override string ToString()
new GalleryPageFactory(() => new ListViewCoreGalleryPage(), "ListView Gallery"),
new GalleryPageFactory(() => new PickerCoreGalleryPage(), "Picker Gallery"),
new GalleryPageFactory(() => new ProgressBarCoreGalleryPage(), "Progress Bar Gallery"),
new GalleryPageFactory(() => new RadioButtonControlPage(), "RadioButton Feature Matrix"),
new GalleryPageFactory(() => new RadioButtonCoreGalleryPage(), "RadioButton Gallery"),
new GalleryPageFactory(() => new ScrollViewCoreGalleryPage(), "ScrollView Gallery"),
new GalleryPageFactory(() => new ShadowFeaturePage(), "Shadow Feature Matrix"),
new GalleryPageFactory(() => new SearchBarCoreGalleryPage(), "Search Bar Gallery"),
new GalleryPageFactory(() => new SliderCoreGalleryPage(), "Slider Gallery"),
new GalleryPageFactory(() => new StepperControlPage(), "Stepper Feature Matrix"),
new GalleryPageFactory(() => new StepperCoreGalleryPage(), "Stepper Gallery"),
new GalleryPageFactory(() => new SwitchCoreGalleryPage(), "Switch Gallery"),
new GalleryPageFactory(() => new SwipeViewCoreGalleryPage(), "SwipeView Gallery"),
new GalleryPageFactory(() => new TimePickerCoreGalleryPage(), "Time Picker Gallery"),
new GalleryPageFactory(() => new WebViewCoreGalleryPage(), "WebView Gallery"),
new GalleryPageFactory(() => new SliderControlPage(), "Slider Feature Matrix"),
new GalleryPageFactory(() => new CheckBoxControlPage(), "CheckBox Feature Matrix"),
new GalleryPageFactory(() => new CollectionViewFeaturePage(), "CollectionView Feature Matrix"),
new GalleryPageFactory(() => new LabelControlPage(), "Label Feature Matrix"),
new GalleryPageFactory(() => new CarouselViewFeaturePage(), "CarouselView Feature Matrix"),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
<?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"
xmlns:local="clr-namespace:Maui.Controls.Sample"
x:Class="Maui.Controls.Sample.CheckBoxControlPage"
x:DataType="local:CheckBoxFeatureMatrixViewModel"
Title="CheckBoxFeature">

<Grid Padding="20"
RowDefinitions="*, Auto, Auto, Auto"
ColumnDefinitions="0.5*, 0.5*"
RowSpacing="10">
<!-- CheckBox Control -->

<CheckBox IsChecked="{Binding IsChecked}"
Color="{Binding Color}"
Grid.ColumnSpan="2"
HorizontalOptions="Center"
VerticalOptions="Center"
IsEnabled="{Binding IsEnabled}"
IsVisible="{Binding IsVisible}"
CheckedChanged="OnCheckBoxCheckedChanged"
AutomationId="CheckBoxControl"/>


<!-- IsChecked Value -->
<Label Grid.Row="1"
Grid.Column="0"
Text="IsChecked:"
FontSize="16"
VerticalTextAlignment="Start"
HorizontalTextAlignment="Start"
Margin="65,0,10,10"/>
<Label Grid.Row="1"
Grid.Column="1"
Text="{Binding IsChecked}"
FontSize="16"
VerticalTextAlignment="Start"
HorizontalTextAlignment="Start"
AutomationId="IsCheckedLabel"/>

<!-- Event Status -->
<Label Grid.Row="2"
Grid.Column="0"
FontSize="16"
Text="Triggered Events:"
IsVisible="{Binding IsEventStatusLabelVisible}"
VerticalTextAlignment="Start"
HorizontalTextAlignment="Start"
Margin="80,0,10,10"/>
<Label Grid.Row="2"
Grid.Column="1"
Text="{Binding CheckedChangedStatus}"
FontSize="16"
VerticalTextAlignment="Start"
HorizontalTextAlignment="Start"
AutomationId="CheckedChangedStatusLabel"
Margin="0,0,10,10"/>

<StackLayout Spacing="10"
Padding="10"
Grid.Row="3"
Grid.ColumnSpan="2">

<Label Text="CheckBox Properties"
FontAttributes="Bold"
FontSize="14"
Margin="0,0,0,10"/>

<StackLayout Orientation="Vertical">
<StackLayout Orientation="Horizontal">
<Label Text="IsChecked"
FontAttributes="Bold"
Margin="0,15,0,0"/>
<Switch IsToggled="{Binding IsChecked}"
AutomationId="IsCheckedSwitch"/>

</StackLayout>
<StackLayout Orientation="Horizontal">
<Label Text="IsEnabled"
FontAttributes="Bold"
Margin="0,15,0,0"/>
<Switch IsToggled="{Binding IsEnabled}"
AutomationId="IsEnabledSwitch"/>
</StackLayout>
<StackLayout Orientation="Horizontal">
<Label Text="IsVisible"
FontAttributes="Bold"
Margin="0,15,0,0"/>
<Switch IsToggled="{Binding IsVisible}"
AutomationId="IsVisibleSwitch"/>
</StackLayout>
</StackLayout>

<!-- Color -->

<Grid ColumnDefinitions="*,0.3*,0.3*,0.3*"
ColumnSpacing="15"
HorizontalOptions="Start">
<Label Text="Color"
FontAttributes="Bold"
VerticalOptions="Center"/>
<Button BackgroundColor="Blue"
Grid.Column="1"
Command="{Binding SetColorCommand}"
CommandParameter="Blue"
AutomationId="BlueColorButton"/>
<Button BackgroundColor="Green"
Grid.Column="2"
Command="{Binding SetColorCommand}"
CommandParameter="Green"
AutomationId="GreenColorButton"/>
<Button BackgroundColor="Gray"
Grid.Column="3"
Command="{Binding SetColorCommand}"
AutomationId="DefaultColorButton"/>
</Grid>

<Button Text="Reset Changes"
Clicked="NavigateToOptionsPage_Clicked"
AutomationId="ResetButton"/>
</StackLayout>
</Grid>
</ContentPage>
Loading
Loading