Skip to content

[2025/04/21] Candidate - In Flight Branch #29037

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 15 commits into from
Apr 23, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
15 commits
Select commit Hold shift + click to select a range
39caefa
[Windows] - Fix Visual State Issue with Picker TextColor After Naviga…
prakashKannanSf3972 Apr 8, 2025
bf27f69
[iOS] Fixed the TargetInvocationException Occurs When Selecting Heade…
Ahamed-Ali Apr 11, 2025
12d2d5e
[iOS] - Resolved Proper Rendering of Dynamic Header/Footer Updates in…
prakashKannanSf3972 Apr 11, 2025
0987b16
[Android] Fixed ScalingCanvas.SetBlur not working (#28911)
NirmalKumarYuvaraj Apr 11, 2025
a009f76
[Windows] Upgrade to Windows App SDK 1.7 (#28499)
MartyIX Apr 11, 2025
9e2cbac
[iOS] Fix FlyoutPage does not respond to changes in the FlyoutLayoutB…
devanathan-vaithiyanathan Apr 11, 2025
0a240f9
[Android] Fixed the Incorrect Text Color Applied to Selected Tab in T…
Ahamed-Ali Apr 11, 2025
624223c
[iOS] Fix for the File.ContentType from MediaPicker not being in vali…
SyedAbdulAzeemSF4852 Apr 11, 2025
57f7f4d
[XC] add IRootObjectProvider (#28310)
StephaneDelcroix Apr 11, 2025
dfeadeb
[Android] picker - focus/unfocus events (#28122)
kubaflo Apr 16, 2025
9576008
[Windows] Fixed the flyout content width not being set correctly afte…
Tamilarasan-Paranthaman Apr 16, 2025
1fb5164
Revert "[Android] picker - focus/unfocus events (#28122)"
PureWeen Apr 16, 2025
16cd5f2
Fixed Test case failure in PR 29037 - [2025/04/21] Candidate (#29049)
HarishKumarSF4517 Apr 21, 2025
76baabc
Fix CarouselView layout SR6 regressions (#29035)
albyrock87 Apr 22, 2025
b1c026c
[Testing] Feature Matrix UITest Cases for CollectionView EmptyView Fe…
NafeelaNazhir Apr 22, 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 eng/Versions.props
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@
<MicrosoftNETWorkloadEmscriptenCurrentManifest90100TransportVersion>9.0.0</MicrosoftNETWorkloadEmscriptenCurrentManifest90100TransportVersion>
<MicrosoftNETWorkloadEmscriptenPackageVersion>$(MicrosoftNETWorkloadEmscriptenCurrentManifest90100TransportVersion)</MicrosoftNETWorkloadEmscriptenPackageVersion>
<!-- wasdk -->
<MicrosoftWindowsAppSDKPackageVersion>1.6.250228001</MicrosoftWindowsAppSDKPackageVersion>
<MicrosoftWindowsAppSDKPackageVersion>1.7.250401001</MicrosoftWindowsAppSDKPackageVersion>
<MicrosoftWindowsSDKBuildToolsPackageVersion>10.0.22621.756</MicrosoftWindowsSDKBuildToolsPackageVersion>
<MicrosoftGraphicsWin2DPackageVersion>1.2.0</MicrosoftGraphicsWin2DPackageVersion>
<MicrosoftWindowsWebView2PackageVersion>1.0.2903.40</MicrosoftWindowsWebView2PackageVersion>
Expand Down
29 changes: 26 additions & 3 deletions src/Controls/src/Build.Tasks/NodeILExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -625,7 +625,8 @@ public static IEnumerable<Instruction> PushServiceProvider(this INode node, ILCo
//Add a SimpleValueTargetProvider and register it as IProvideValueTarget, IReferenceProvider and IProvideParentValues
if (createAllServices
|| requiredServices.Contains(module.ImportReference(context.Cache, ("Microsoft.Maui.Controls", "Microsoft.Maui.Controls.Xaml", "IProvideParentValues")), TypeRefComparer.Default)
|| requiredServices.Contains(module.ImportReference(context.Cache, ("Microsoft.Maui.Controls", "Microsoft.Maui.Controls.Xaml", "IReferenceProvider")), TypeRefComparer.Default))
|| requiredServices.Contains(module.ImportReference(context.Cache, ("Microsoft.Maui.Controls", "Microsoft.Maui.Controls.Xaml", "IReferenceProvider")), TypeRefComparer.Default)
|| requiredServices.Contains(module.ImportReference(context.Cache, ("Microsoft.Maui.Controls", "Microsoft.Maui.Controls.Xaml", "IRootObjectProvider")), TypeRefComparer.Default))
{
alreadyContainsProvideValueTarget = true;
var pushParentIl = node.PushParentObjectsArray(context).ToList();
Expand All @@ -644,9 +645,25 @@ public static IEnumerable<Instruction> PushServiceProvider(this INode node, ILCo
foreach (var instruction in PushNamescopes(node, context, module))
yield return instruction;

yield return Create(Ldc_I4_0); //don't ask
//rootObject
if (context.Root is VariableDefinition rootVariable)
yield return Create(Ldloc, rootVariable);
else if (context.Root is FieldReference rootField)
{
yield return Create(Ldarg_0);
yield return Create(Ldfld, rootField);
}
else
yield return Create(Ldnull);

yield return Create(Newobj, module.ImportCtorReference(context.Cache,
("Microsoft.Maui.Controls.Xaml", "Microsoft.Maui.Controls.Xaml.Internals", "SimpleValueTargetProvider"), paramCount: 4));
type: ("Microsoft.Maui.Controls.Xaml", "Microsoft.Maui.Controls.Xaml.Internals", "SimpleValueTargetProvider"),
parameterTypes: [
("mscorlib", "System", "Object[]"),
("mscorlib", "System", "Object"),
("Microsoft.Maui.Controls", "Microsoft.Maui.Controls.Internals", "INameScope[]"),
("mscorlib", "System", "Object"),
]));

//store the provider so we can register it again with a different key
yield return Create(Dup);
Expand All @@ -660,6 +677,12 @@ public static IEnumerable<Instruction> PushServiceProvider(this INode node, ILCo
yield return Create(Call, module.ImportMethodReference(context.Cache, ("mscorlib", "System", "Type"), methodName: "GetTypeFromHandle", parameterTypes: new[] { ("mscorlib", "System", "RuntimeTypeHandle") }, isStatic: true));
yield return Create(Ldloc, refProvider);
yield return Create(Callvirt, addService);

yield return Create(Dup); //Keep the serviceProvider on the stack
yield return Create(Ldtoken, module.ImportReference(context.Cache, ("Microsoft.Maui.Controls", "Microsoft.Maui.Controls.Xaml", "IRootObjectProvider")));
yield return Create(Call, module.ImportMethodReference(context.Cache, ("mscorlib", "System", "Type"), methodName: "GetTypeFromHandle", parameterTypes: new[] { ("mscorlib", "System", "RuntimeTypeHandle") }, isStatic: true));
yield return Create(Ldloc, refProvider);
yield return Create(Callvirt, addService);
}
}

Expand Down
10 changes: 8 additions & 2 deletions src/Controls/src/Build.Tasks/XamlCache.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using Microsoft.Maui.Controls.XamlC;
using Mono.Cecil;
using Mono.Cecil.Cil;
using Mono.Cecil.Rocks;

namespace Microsoft.Maui.Controls.Build.Tasks;

Expand Down Expand Up @@ -38,8 +39,13 @@ public TypeDefinition Resolve(TypeReference typeReference) =>
public FieldReference GetOrAddFieldReference((ModuleDefinition module, string fieldRefKey) key, Func<(ModuleDefinition module, string fieldRefKey), FieldReference> valueFactory) =>
GetOrAdd(_fieldReferenceCache, key, valueFactory);

public TypeReference GetOrAddTypeReference(ModuleDefinition module, (string assemblyName, string clrNamespace, string typeName) type) =>
GetOrAdd(_typeReferenceCache, (module, type.ToString()), x => x.module.ImportReference(x.module.GetTypeDefinition(this, type)));
public TypeReference GetOrAddTypeReference(ModuleDefinition module, (string assemblyName, string clrNamespace, string typeName) type) => GetOrAdd(_typeReferenceCache, (module, type.ToString()), x =>
{
if (type.typeName.EndsWith("[]", StringComparison.InvariantCultureIgnoreCase))
return x.module.GetTypeDefinition(this, (type.assemblyName, type.clrNamespace, type.typeName.Substring(0, type.typeName.Length-2))).MakeArrayType();
else
return x.module.ImportReference(x.module.GetTypeDefinition(this, type));
});

public TypeReference GetOrAddTypeReference(ModuleDefinition module, string typeKey, Func<(ModuleDefinition module, string typeKey), TypeReference> valueFactory) =>
GetOrAdd(_typeReferenceCache, (module, typeKey), valueFactory);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,8 @@ void HandlePropertyChanged(object sender, PropertyChangedEventArgs e)
UpdateBackground();
else if (e.PropertyName == PlatformConfiguration.iOSSpecific.FlyoutPage.ApplyShadowProperty.PropertyName)
UpdateApplyShadow(((FlyoutPage)Element).OnThisPlatform().GetApplyShadow());
else if (e.PropertyName == Microsoft.Maui.Controls.FlyoutPage.FlyoutLayoutBehaviorProperty.PropertyName)
UpdateFlyoutLayoutBehaviorChanges();
else if (e.PropertyName == PlatformConfiguration.iOSSpecific.Page.PrefersHomeIndicatorAutoHiddenProperty.PropertyName ||
e.PropertyName == PlatformConfiguration.iOSSpecific.Page.PrefersStatusBarHiddenProperty.PropertyName)
UpdatePageSpecifics();
Expand Down Expand Up @@ -476,6 +478,25 @@ void LayoutChildren(bool animated)
UpdateClickOffViewFrame();
}

void UpdateFlyoutLayoutBehaviorChanges()
{
LayoutChildren(true);
if (FlyoutPage is null)
return;
FlyoutLayoutBehavior flyoutBehavior = FlyoutPage.FlyoutLayoutBehavior;
bool shouldPresent = FlyoutPageController.ShouldShowSplitMode;
if (flyoutBehavior == FlyoutLayoutBehavior.Popover || flyoutBehavior == FlyoutLayoutBehavior.Default)
{
shouldPresent = false;
}

if (shouldPresent != FlyoutPage.IsPresented)
{
((IElementController)Element).SetValueFromRenderer(FlyoutPage.IsPresentedProperty, shouldPresent);
UpdateLeftBarButton();
}
}

void PackContainers()
{
_detailController.View.BackgroundColor = new UIColor(1, 1, 1, 1);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,10 @@ public override void ConstrainTo(CGSize constraint)

public override CGSize Measure()
{
return new CGSize(_constraint.Width, _constraint.Height);
// Go through the measure pass even if the constraints are fixed
// to ensure arrange pass has the appropriate desired size in place.
PlatformHandler.VirtualView.Measure(_constraint.Width, _constraint.Height);
return _constraint;
}

protected override (bool, Size) NeedsContentSizeUpdate(Size currentSize)
Expand All @@ -42,7 +45,7 @@ protected override (bool, Size) NeedsContentSizeUpdate(Size currentSize)

protected override bool AttributesConsistentWithConstrainedDimension(UICollectionViewLayoutAttributes attributes)
{
return false;
return _constraint.IsCloseTo(attributes.Frame.Size);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,9 @@ protected override string DetermineCellReuseId(NSIndexPath indexPath)
return base.DetermineCellReuseId(NSIndexPath.FromItemSection(itemIndex, 0));
}

private protected override (Type CellType, string CellTypeReuseId) DetermineTemplatedCellType()
=> (typeof(CarouselTemplatedCell), "maui_carousel");

protected override void RegisterViewTypes()
{
CollectionView.RegisterClassForCell(typeof(CarouselTemplatedCell), CarouselTemplatedCell.ReuseId);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -503,9 +503,9 @@ protected virtual string DetermineCellReuseId(NSIndexPath indexPath)
var dataTemplate = ItemsView.ItemTemplate.SelectDataTemplate(item, ItemsView);

var cellOrientation = ItemsViewLayout.ScrollDirection == UICollectionViewScrollDirection.Vertical ? "v" : "h";
var cellType = ItemsViewLayout.ScrollDirection == UICollectionViewScrollDirection.Vertical ? typeof(VerticalCell) : typeof(HorizontalCell);
(Type cellType, var cellTypeReuseId) = DetermineTemplatedCellType();

var reuseId = $"_maui_{cellOrientation}_{dataTemplate.Id}";
var reuseId = $"_{cellTypeReuseId}_{cellOrientation}_{dataTemplate.Id}";

if (!_cellReuseIds.Contains(reuseId))
{
Expand All @@ -521,6 +521,11 @@ protected virtual string DetermineCellReuseId(NSIndexPath indexPath)
: VerticalDefaultCell.ReuseId;
}

private protected virtual (Type CellType, string CellTypeReuseId) DetermineTemplatedCellType()
{
return (ItemsViewLayout.ScrollDirection == UICollectionViewScrollDirection.Vertical ? typeof(VerticalCell) : typeof(HorizontalCell), "maui");
}

[Obsolete("Use DetermineCellReuseId(NSIndexPath indexPath) instead.")]
protected virtual string DetermineCellReuseId()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,7 @@ protected override CarouselViewController2 CreateController(CarouselView newElem

protected override UICollectionViewLayout SelectLayout()
{
bool IsHorizontal = VirtualView.ItemsLayout.Orientation == ItemsLayoutOrientation.Horizontal;
UICollectionViewScrollDirection scrollDirection = IsHorizontal ? UICollectionViewScrollDirection.Horizontal : UICollectionViewScrollDirection.Vertical;
bool isHorizontal = VirtualView.ItemsLayout.Orientation == ItemsLayoutOrientation.Horizontal;

NSCollectionLayoutDimension itemWidth = NSCollectionLayoutDimension.CreateFractionalWidth(1);
NSCollectionLayoutDimension itemHeight = NSCollectionLayoutDimension.CreateFractionalHeight(1);
Expand All @@ -55,7 +54,7 @@ protected override UICollectionViewLayout SelectLayout()
return null;
}
double sectionMargin = 0.0;
if (!IsHorizontal)
if (!isHorizontal)
{
sectionMargin = VirtualView.PeekAreaInsets.VerticalThickness / 2;
var newGroupHeight = environment.Container.ContentSize.Height - VirtualView.PeekAreaInsets.VerticalThickness;
Expand All @@ -81,19 +80,19 @@ protected override UICollectionViewLayout SelectLayout()

if (OperatingSystem.IsIOSVersionAtLeast(16))
{
group = IsHorizontal ? NSCollectionLayoutGroup.GetHorizontalGroup(groupSize, item, 1) :
group = isHorizontal ? NSCollectionLayoutGroup.GetHorizontalGroup(groupSize, item, 1) :
NSCollectionLayoutGroup.GetVerticalGroup(groupSize, item, 1);
}
else
{
group = IsHorizontal ? NSCollectionLayoutGroup.CreateHorizontal(groupSize, item, 1) :
group = isHorizontal ? NSCollectionLayoutGroup.CreateHorizontal(groupSize, item, 1) :
NSCollectionLayoutGroup.CreateVertical(groupSize, item, 1);
}

// Create our section layout
var section = NSCollectionLayoutSection.Create(group: group);
section.InterGroupSpacing = itemSpacing;
section.OrthogonalScrollingBehavior = IsHorizontal ? UICollectionLayoutSectionOrthogonalScrollingBehavior.GroupPagingCentered : UICollectionLayoutSectionOrthogonalScrollingBehavior.None;
section.OrthogonalScrollingBehavior = isHorizontal ? UICollectionLayoutSectionOrthogonalScrollingBehavior.GroupPagingCentered : UICollectionLayoutSectionOrthogonalScrollingBehavior.None;
section.VisibleItemsInvalidationHandler = (items, offset, env) =>
{
//This will allow us to SetPosition when we are scrolling the items
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ public CollectionViewHandler2(PropertyMapper mapper = null) : base(mapper ?? Map
[StructuredItemsView.FooterTemplateProperty.PropertyName] = MapFooterTemplate,
[StructuredItemsView.HeaderProperty.PropertyName] = MapHeaderTemplate,
[StructuredItemsView.FooterProperty.PropertyName] = MapFooterTemplate,
[GroupableItemsView.GroupHeaderTemplateProperty.PropertyName] = MapHeaderTemplate,
[GroupableItemsView.GroupFooterTemplateProperty.PropertyName] = MapFooterTemplate,
};
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#nullable disable
using CoreGraphics;
using Foundation;
using Microsoft.Maui.Graphics;
using UIKit;

namespace Microsoft.Maui.Controls.Handlers.Items2
{
internal sealed class CarouselTemplatedCell2 : TemplatedCell2
{
internal new const string ReuseId = "Microsoft.Maui.Controls.CarouselTemplatedCell2";

[Export("initWithFrame:")]
[Microsoft.Maui.Controls.Internals.Preserve(Conditional = true)]
public CarouselTemplatedCell2(CGRect frame) : base(frame)
{
}

private protected override Size GetMeasureConstraints(UICollectionViewLayoutAttributes preferredAttributes)
=> preferredAttributes.Size.ToSize();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,9 @@ protected override string DetermineCellReuseId(NSIndexPath indexPath)
return base.DetermineCellReuseId(itemIndex);
}

private protected override (Type CellType, string CellTypeReuseId) DetermineTemplatedCellType()
=> (typeof(CarouselTemplatedCell2), CarouselTemplatedCell2.ReuseId);

protected override Items.IItemsViewSource CreateItemsViewSource()
{
var itemsSource = ItemsSourceFactory2.CreateForCarouselView(ItemsView.ItemsSource, this, ItemsView.Loop);
Expand Down Expand Up @@ -506,54 +509,49 @@ async Task UpdateInitialPosition()
return;
}

int position = carousel.Position;
var currentItem = carousel.CurrentItem;

if (currentItem != null)
{
// Sometimes the item could be just being removed while we navigate back to the CarouselView
var positionCurrentItem = ItemsSource.GetIndexForItem(currentItem).Row;
if (positionCurrentItem != -1)
{
position = positionCurrentItem;
}
}

var projectedPosition = NSIndexPath.FromItemSection(position, _section);

if (LoopItemsSource.Loop)
{
//We need to set the position to the correct position since we added 1 item at the beginning
projectedPosition = GetScrollToIndexPath(position);
}

var uICollectionViewScrollPosition = IsHorizontal ? UICollectionViewScrollPosition.CenteredHorizontally : UICollectionViewScrollPosition.CenteredVertically;

await Task.Delay(100).ContinueWith((t) =>
await Task.Delay(100).ContinueWith(_ =>
{
MainThread.BeginInvokeOnMainThread(() =>
{
if (!IsViewLoaded)
{
return;
}

InitialPositionSet = true;

if (ItemsSource is null || ItemsSource.ItemCount == 0)
{
return;
}

int position = carousel.Position;
var currentItem = carousel.CurrentItem;

if (currentItem != null)
{
// Sometimes the item could be just being removed while we navigate back to the CarouselView
var positionCurrentItem = ItemsSource.GetIndexForItem(currentItem).Row;
if (positionCurrentItem != -1)
{
position = positionCurrentItem;
}
}

var projectedPosition = LoopItemsSource.Loop
? GetScrollToIndexPath(position) // We need to set the position to the correct position since we added 1 item at the beginning
: NSIndexPath.FromItemSection(position, _section);

var uICollectionViewScrollPosition = IsHorizontal ? UICollectionViewScrollPosition.CenteredHorizontally : UICollectionViewScrollPosition.CenteredVertically;

CollectionView.ScrollToItem(projectedPosition, uICollectionViewScrollPosition, false);

//Set the position on VirtualView to update the CurrentItem also
SetPosition(position);

UpdateVisualStates();
});

});

}

void UpdateVisualStates()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,20 +61,14 @@ protected override void RegisterViewTypes()
private protected override void RegisterSupplementaryViews(UICollectionElementKindSection kind)
{
base.RegisterSupplementaryViews(kind);
if (IsHorizontal)
{
CollectionView.RegisterClassForSupplementaryView(typeof(HorizontalSupplementaryView2),
kind, HorizontalSupplementalView2ReuseId);
CollectionView.RegisterClassForSupplementaryView(typeof(HorizontalDefaultSupplementalView2),
kind, HorizontalDefaultSupplementalView2ReuseId);
}
else
{
CollectionView.RegisterClassForSupplementaryView(typeof(VerticalSupplementaryView2),
kind, VerticalSupplementaryView2ReuseId);
CollectionView.RegisterClassForSupplementaryView(typeof(VerticalDefaultSupplementalView2),
kind, VerticalDefaultSupplementalView2ReuseId);
}
CollectionView.RegisterClassForSupplementaryView(typeof(HorizontalSupplementaryView2),
kind, HorizontalSupplementalView2ReuseId);
CollectionView.RegisterClassForSupplementaryView(typeof(HorizontalDefaultSupplementalView2),
kind, HorizontalDefaultSupplementalView2ReuseId);
CollectionView.RegisterClassForSupplementaryView(typeof(VerticalSupplementaryView2),
kind, VerticalSupplementaryView2ReuseId);
CollectionView.RegisterClassForSupplementaryView(typeof(VerticalDefaultSupplementalView2),
kind, VerticalDefaultSupplementalView2ReuseId);
}

string DetermineViewReuseId(NSString elementKind)
Expand Down Expand Up @@ -133,7 +127,9 @@ void UpdateTemplatedSupplementaryView(TemplatedCell2 cell, NSString elementKind,

var bindingContext = ItemsSource.Group(indexPath);

cell.isHeaderOrFooterChanged = true;
cell.Bind(template, bindingContext, ItemsView);
cell.isHeaderOrFooterChanged = false;

// if (cell is ItemsViewCell2)
// {
Expand Down
Loading
Loading