diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json
index 9c2834be3038..60580813dcc0 100644
--- a/.config/dotnet-tools.json
+++ b/.config/dotnet-tools.json
@@ -24,7 +24,7 @@
"rollForward": false
},
"microsoft.dotnet.xharness.cli": {
- "version": "9.0.0-prerelease.25167.9",
+ "version": "9.0.0-prerelease.25207.3",
"commands": [
"xharness"
],
diff --git a/.github/ISSUE_TEMPLATE/bug-report.yml b/.github/ISSUE_TEMPLATE/bug-report.yml
index 75922c1cb117..d3d8c3a585b9 100644
--- a/.github/ISSUE_TEMPLATE/bug-report.yml
+++ b/.github/ISSUE_TEMPLATE/bug-report.yml
@@ -42,7 +42,10 @@ body:
label: Version with bug
description: In what version do you see this issue? Run `dotnet workload list` to find your version.
options:
+ - 10.0.0-preview.3
+ - 10.0.0-preview.2
- 10.0.0-preview.1
+ - 9.0.60 SR6
- 9.0.50 SR5
- 9.0.40 SR4
- 9.0.30 SR3
@@ -165,7 +168,10 @@ body:
- 9.0.30 SR3
- 9.0.40 SR4
- 9.0.50 SR5
+ - 9.0.60 SR6
- 10.0.0-preview.1
+ - 10.0.0-preview.2
+ - 10.0.0-preview.3
validations:
required: true
- type: dropdown
diff --git a/eng/Publishing.props b/eng/Publishing.props
index 96b340af297c..7fb3d1d57d87 100644
--- a/eng/Publishing.props
+++ b/eng/Publishing.props
@@ -9,11 +9,11 @@
- <_UploadPathRoot>maui-sdk
+ <_UploadPathRoot>maui
-
+
true
false
diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml
index 7585926542db..552973e49cb7 100644
--- a/eng/Version.Details.xml
+++ b/eng/Version.Details.xml
@@ -135,17 +135,17 @@
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
831d23e56149cd59c40fc00c7feb7c5334bd19c4
-
+
https://github.com/dotnet/xharness
- 8fa551353a0b2c90afb82c507f23afdf966d57c5
+ aed708d126f0776c81966db1ca17278edbef8279
-
+
https://github.com/dotnet/xharness
- 8fa551353a0b2c90afb82c507f23afdf966d57c5
+ aed708d126f0776c81966db1ca17278edbef8279
-
+
https://github.com/dotnet/xharness
- 8fa551353a0b2c90afb82c507f23afdf966d57c5
+ aed708d126f0776c81966db1ca17278edbef8279
diff --git a/eng/Versions.props b/eng/Versions.props
index f68a4b3c97ba..fd779afa33d5 100644
--- a/eng/Versions.props
+++ b/eng/Versions.props
@@ -2,7 +2,7 @@
9
0
- 60
+ 70
9.0.100
ci.net9
@@ -125,9 +125,9 @@
<_HarfBuzzSharpVersion>8.3.0.1
<_SkiaSharpNativeAssetsVersion>0.0.0-commit.e57e2a11dac4ccc72bea52939dede49816842005.1728
7.0.120
- 9.0.0-prerelease.25167.9
- 9.0.0-prerelease.25167.9
- 9.0.0-prerelease.25167.9
+ 9.0.0-prerelease.25207.3
+ 9.0.0-prerelease.25207.3
+ 9.0.0-prerelease.25207.3
0.9.2
2.0.0.4
1.3.0
diff --git a/eng/pipelines/maui-release-internal.yml b/eng/pipelines/maui-release-internal.yml
new file mode 100644
index 000000000000..6bf3ab993b68
--- /dev/null
+++ b/eng/pipelines/maui-release-internal.yml
@@ -0,0 +1,125 @@
+trigger: none
+pr: none
+
+parameters:
+- name: ghRepo
+ displayName: GitHub repository name
+ type: string
+ default: maui
+
+- name: ghOwner
+ displayName: GitHub repository owner
+ type: string
+ default: dotnet
+
+- name: commitHash
+ displayName: Commit hash to download nupkgs from
+ type: string
+ default: skip
+
+- name: VM_IMAGE_HOST
+ type: object
+ default:
+ name: NetCore1ESPool-Internal
+ image: 1es-windows-2022
+ os: windows
+
+variables:
+- template: /eng/common/templates/variables/pool-providers.yml@self
+- group: DotNetBuilds storage account read tokens
+- group: AzureDevOps-Artifact-Feeds-Pats
+
+resources:
+ repositories:
+ - repository: 1ESPipelineTemplates
+ type: git
+ name: 1ESPipelineTemplates/1ESPipelineTemplates
+ ref: refs/tags/release
+
+extends:
+ ${{ if ne(variables['Build.Reason'], 'PullRequest') }}:
+ template: v1/1ES.Official.PipelineTemplate.yml@1ESPipelineTemplates
+ ${{ else }}:
+ template: v1/1ES.Unofficial.PipelineTemplate.yml@1ESPipelineTemplates
+ parameters:
+ pool: ${{ parameters.VM_IMAGE_HOST }}
+ sdl:
+ binskim:
+ scanOutputDirectoryOnly: true
+ codeql:
+ runSourceLanguagesInSourceAnalysis: true
+ policheck:
+ enabled: true
+ spotBugs:
+ enabled: false
+ justification: 'Failing with "Could not successfully find the java tool launcher"'
+ sourceRepositoriesToScan:
+ exclude:
+ - repository: yaml-templates
+ suppression:
+ suppressionFile: $(Build.SourcesDirectory)\eng\automation\guardian\source.gdnsuppress
+ stages:
+ - stage: publish_maestro
+ displayName: Publish to Workload Set channel
+ dependsOn: []
+ jobs:
+ - job: publish_maestro
+ displayName: Publish to Workload Set channel
+ pool: ${{ parameters.VM_IMAGE_HOST }}
+ timeoutInMinutes: 240
+ workspace:
+ clean: all
+ steps:
+ - ${{ if eq(parameters.commitHash, 'skip') }}:
+ - script: echo parameters.commitHash was not set, skipping...
+ displayName: Skip push
+ - ${{ else }}:
+ - script: |
+ echo ##vso[task.setvariable variable=COMMIT]${{ parameters.commitHash }}
+ displayName: Set COMMIT
+
+ - task: AzureCLI@2
+ displayName: Add build to workload set channel
+ inputs:
+ azureSubscription: "Darc: Maestro Production"
+ scriptType: pscore
+ scriptLocation: inlineScript
+ inlineScript: |
+ Write-Host "Getting BAR ID for commit: $(COMMIT)"
+ . $(Build.SourcesDirectory)\eng\common\tools.ps1
+ $darc = Get-Darc
+ $buildJson = & $darc get-build --ci --repo "${{ parameters.ghRepo }}" --commit "$(COMMIT)" --output-format json --azdev-pat $(System.AccessToken)
+ Write-Host "`n$buildJson`n"
+ $barId = $buildJson | ConvertFrom-Json | Select-Object -ExpandProperty "id" -First 1
+ Write-Host "Got the Bar ID: $barId for commit $(COMMIT) on repo ${{ parameters.ghRepo }}"
+ if ($barId -eq $null) {
+ Write-Error "Could not find a build for commit $(COMMIT) on repo ${{ parameters.ghRepo }}"
+ exit 1
+ }
+ Write-Host "Getting drop for Bar ID: $barId"
+ & $darc gather-drop --ci --id $barId -o "$(Build.StagingDirectory)\nupkgs" --azdev-pat $(System.AccessToken) --verbose
+ Write-Host "List downloaded artifacts"
+ Get-ChildItem -Name -Recurse -Path $(Build.StagingDirectory)
+ $manifestPack = Get-ChildItem -Path "$(Build.StagingDirectory)\nupkgs\shipping\packages\" -Filter "*.Manifest-*.nupkg" | Select-Object -First 1
+ $workloadSetsChannel = ""
+ $workloadSetsFeed = ""
+ if ($manifestPack -like "*.Manifest-8.0*") {
+ $workloadSetsChannel = ".NET 8 Workload Release"
+ $workloadSetsFeed = "dotnet8-workloads"
+ }
+ if ($manifestPack -like "*.Manifest-9.0*") {
+ $workloadSetsChannel = ".NET 9 Workload Release"
+ $workloadSetsFeed = "dotnet9-workloads"
+ }
+ if ($manifestPack -like "*.Manifest-10.0*") {
+ $workloadSetsChannel = ".NET 10 Workload Release"
+ $workloadSetsFeed = "dotnet10-workloads"
+ }
+ if (!$workloadSetsChannel -or !$workloadSetsFeed) {
+ Write-Error "Could not determine the workload sets channel or feed for the manifest pack '$manifestPack'"
+ exit 1
+ }
+ Write-Host "##vso[task.setvariable variable=WorkloadSetsFeedName;]$workloadSetsFeed"
+ Write-Host "Adding build ID '$barId' to channel '$workloadSetsChannel' and feed '$workloadSetsFeed'"
+ & $darc add-build-to-channel --ci --channel "$workloadSetsChannel" --id "$barId" --skip-assets-publishing --azdev-pat $(System.AccessToken) --verbose
+
diff --git a/src/Compatibility/Core/tests/Compatibility.UnitTests/StackLayoutUnitTests.cs b/src/Compatibility/Core/tests/Compatibility.UnitTests/StackLayoutUnitTests.cs
index d03e65ee1398..6b79945ddca7 100644
--- a/src/Compatibility/Core/tests/Compatibility.UnitTests/StackLayoutUnitTests.cs
+++ b/src/Compatibility/Core/tests/Compatibility.UnitTests/StackLayoutUnitTests.cs
@@ -341,7 +341,7 @@ public void TestVisibility()
};
var handler = Substitute.For();
- stack.Handler = handler;
+ child1.Handler = handler;
stack.Layout(new Rect(0, 0, 100, 100));
@@ -352,8 +352,11 @@ public void TestVisibility()
child1.IsVisible = false;
- // Verify that the visibility change invalidated the layout, and simulate a native layout update
+ // Verify that the visibility change invalidated the child
+ // which will propagate the invalidation up through the platform tree.
AssertInvalidated(handler);
+
+ // Then simulate a native layout update
stack.ForceLayout();
Assert.False(child1.IsVisible);
@@ -661,14 +664,16 @@ public void PaddingResizeTest()
var handler = Substitute.For();
- outerLayout.Handler = handler;
+ innerStack.Handler = handler;
outerLayout.Layout(new Rect(0, 0, 100, 100));
var beforeSize = innerStack.Bounds.Size;
innerStack.Padding = new Thickness(30);
- // Verify that the Padding change invalidated the layout, and simulate a native layout update
+ // Verify that the padding change invalidated the inner stack
+ // which will propagate the invalidation up through the platform tree.
AssertInvalidated(handler);
+ // Now simulate a native layout update
outerLayout.ForceLayout();
var afterSize = innerStack.Bounds.Size;
diff --git a/src/Controls/src/Core/Compatibility/Handlers/ListView/iOS/CellRenderer.cs b/src/Controls/src/Core/Compatibility/Handlers/ListView/iOS/CellRenderer.cs
index 1d34dcddd347..460b565bb996 100644
--- a/src/Controls/src/Core/Compatibility/Handlers/ListView/iOS/CellRenderer.cs
+++ b/src/Controls/src/Core/Compatibility/Handlers/ListView/iOS/CellRenderer.cs
@@ -32,12 +32,12 @@ protected override UITableViewCell CreatePlatformElement()
var tv = VirtualView.TableView;
VirtualView.ReusableCell = null;
VirtualView.TableView = null;
+ _tableView = new(tv);
return GetCell(VirtualView, reusableCell, tv);
}
public virtual UITableViewCell GetCell(Cell item, UITableViewCell reusableCell, UITableView tv)
{
- _tableView = new(tv);
Performance.Start(out string reference);
var tvc = reusableCell as CellTableViewCell ?? new CellTableViewCell(UITableViewCellStyle.Default, item.GetType().FullName);
diff --git a/src/Controls/src/Core/Compatibility/Handlers/ListView/iOS/ListViewRenderer.cs b/src/Controls/src/Core/Compatibility/Handlers/ListView/iOS/ListViewRenderer.cs
index 4540c31278a0..7eb1d1e67431 100644
--- a/src/Controls/src/Core/Compatibility/Handlers/ListView/iOS/ListViewRenderer.cs
+++ b/src/Controls/src/Core/Compatibility/Handlers/ListView/iOS/ListViewRenderer.cs
@@ -986,6 +986,7 @@ internal class ListViewDataSource : UITableViewSource
readonly WeakReference _uiTableView;
readonly WeakReference _uiTableViewController;
protected readonly WeakReference _list;
+ readonly HashSet _contextActionsCells = new();
bool _isDragging;
bool _setupSelection;
bool _selectionFromNative;
@@ -1113,6 +1114,10 @@ public override UITableViewCell GetCell(UITableView tableView, NSIndexPath index
SetCellBackgroundColor(platformCell, bgColor);
PreserveActivityIndicatorState(cell);
Performance.Stop(reference);
+
+ if(platformCell is ContextActionsCell contextActionsCell)
+ _contextActionsCells.Add(contextActionsCell);
+
return platformCell;
}
@@ -1495,12 +1500,16 @@ protected override void Dispose(bool disposing)
if (disposing)
{
- if (!_list.TryGetTarget(out var list))
+ if (_list.TryGetTarget(out var list))
{
list.ItemSelected -= OnItemSelected;
WatchShortNameCollection(false);
}
+ foreach (var cell in _contextActionsCells)
+ cell.Dispose();
+ _contextActionsCells.Clear();
+
_templateToId = null;
}
diff --git a/src/Controls/src/Core/ContentPresenter.cs b/src/Controls/src/Core/ContentPresenter.cs
index 590a0802e913..fb517a905715 100644
--- a/src/Controls/src/Core/ContentPresenter.cs
+++ b/src/Controls/src/Core/ContentPresenter.cs
@@ -130,10 +130,5 @@ Size ICrossPlatformLayout.CrossPlatformArrange(Rect bounds)
this.ArrangeContent(bounds);
return bounds.Size;
}
-
- private protected override void InvalidateMeasureLegacy(InvalidationTrigger trigger, int depth, int depthLeveltoInvalidate)
- {
- base.InvalidateMeasureLegacy(trigger, depth, 1);
- }
}
}
\ No newline at end of file
diff --git a/src/Controls/src/Core/Handlers/Items/iOS/ItemsViewCell.cs b/src/Controls/src/Core/Handlers/Items/iOS/ItemsViewCell.cs
index 61b5a38d7d5e..a6be4d5c3924 100644
--- a/src/Controls/src/Core/Handlers/Items/iOS/ItemsViewCell.cs
+++ b/src/Controls/src/Core/Handlers/Items/iOS/ItemsViewCell.cs
@@ -24,9 +24,13 @@ protected ItemsViewCell(CGRect frame) : base(frame)
}
protected void InitializeContentConstraints(UIView platformView)
+ {
+ SetupPlatformView(platformView, true);
+ }
+
+ private protected void SetupPlatformView(UIView platformView, bool autoLayout = false)
{
ContentView.TranslatesAutoresizingMaskIntoConstraints = false;
- platformView.TranslatesAutoresizingMaskIntoConstraints = false;
ContentView.AddSubview(platformView);
@@ -36,12 +40,15 @@ protected void InitializeContentConstraints(UIView platformView)
ContentView.LeadingAnchor.ConstraintEqualTo(LeadingAnchor).Active = true;
ContentView.TrailingAnchor.ConstraintEqualTo(TrailingAnchor).Active = true;
- // And we want the ContentView to be the same size as the root renderer for the Forms element
- // TODO: we should probably remove this to support `Margin` applied to the cell's root `VirtualView`
- ContentView.TopAnchor.ConstraintEqualTo(platformView.TopAnchor).Active = true;
- ContentView.BottomAnchor.ConstraintEqualTo(platformView.BottomAnchor).Active = true;
- ContentView.LeadingAnchor.ConstraintEqualTo(platformView.LeadingAnchor).Active = true;
- ContentView.TrailingAnchor.ConstraintEqualTo(platformView.TrailingAnchor).Active = true;
+ if (autoLayout)
+ {
+ // And we want the ContentView to be the same size as the root renderer for the Forms element
+ platformView.TranslatesAutoresizingMaskIntoConstraints = false;
+ ContentView.TopAnchor.ConstraintEqualTo(platformView.TopAnchor).Active = true;
+ ContentView.BottomAnchor.ConstraintEqualTo(platformView.BottomAnchor).Active = true;
+ ContentView.LeadingAnchor.ConstraintEqualTo(platformView.LeadingAnchor).Active = true;
+ ContentView.TrailingAnchor.ConstraintEqualTo(platformView.TrailingAnchor).Active = true;
+ }
}
public abstract void ConstrainTo(nfloat constant);
diff --git a/src/Controls/src/Core/Handlers/Items/iOS/ItemsViewController.cs b/src/Controls/src/Core/Handlers/Items/iOS/ItemsViewController.cs
index cbcdf2cc8993..17494ee38c64 100644
--- a/src/Controls/src/Core/Handlers/Items/iOS/ItemsViewController.cs
+++ b/src/Controls/src/Core/Handlers/Items/iOS/ItemsViewController.cs
@@ -1,8 +1,8 @@
#nullable disable
using System;
using System.Collections.Generic;
-using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;
+using System.Linq;
using CoreGraphics;
using Foundation;
using Microsoft.Maui.Controls.Internals;
@@ -200,19 +200,42 @@ public override void ViewWillLayoutSubviews()
{
ConstrainItemsToBounds();
- if (CollectionView is Items.MauiCollectionView { NeedsCellLayout: true } collectionView)
+ var mauiCollectionView = CollectionView as MauiCollectionView;
+ var needsCellLayout = mauiCollectionView?.NeedsCellLayout is true;
+ if (needsCellLayout)
{
InvalidateLayoutIfItemsMeasureChanged();
- collectionView.NeedsCellLayout = false;
+ mauiCollectionView.NeedsCellLayout = false;
}
base.ViewWillLayoutSubviews();
+
+ if (needsCellLayout || !_laidOut)
+ {
+ // We don't want to mess up with ContentOffset while refreshing, given that's also gonna cause
+ // a change in the content's offset Y.
+ if (!IsRefreshing())
+ {
+ MeasureSupplementaryViews();
+ LayoutSupplementaryViews();
+ }
+ }
+
InvalidateMeasureIfContentSizeChanged();
- LayoutEmptyView();
_laidOut = true;
}
+ private protected virtual void MeasureSupplementaryViews()
+ {
+ RemeasureLayout(_emptyViewFormsElement, _emptyUIView);
+ }
+
+ private protected virtual void LayoutSupplementaryViews()
+ {
+ LayoutEmptyView();
+ }
+
void InvalidateLayoutIfItemsMeasureChanged()
{
var visibleCells = CollectionView.VisibleCells;
@@ -237,6 +260,21 @@ void InvalidateLayoutIfItemsMeasureChanged()
}
}
+ bool IsRefreshing()
+ {
+ var subviews = CollectionView.Subviews;
+ var subviewsLength = subviews.Length;
+ for (int i = 0; i < subviewsLength; i++)
+ {
+ if (subviews[i] is UIRefreshControl { Refreshing: true })
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
void MauiCollectionView.ICustomMauiCollectionViewDelegate.MovedToWindow(UIView view)
{
if (CollectionView?.Window != null)
@@ -549,15 +587,58 @@ protected virtual CGRect DetermineEmptyViewFrame()
protected void RemeasureLayout(VisualElement formsElement)
{
+ Size size;
if (IsHorizontal)
{
var request = formsElement.Measure(double.PositiveInfinity, CollectionView.Frame.Height);
- formsElement.Arrange(new Rect(0, 0, request.Width, CollectionView.Frame.Height));
+ size = new Size(request.Width, CollectionView.Frame.Height);
}
else
{
var request = formsElement.Measure(CollectionView.Frame.Width, double.PositiveInfinity);
- formsElement.Arrange(new Rect(0, 0, CollectionView.Frame.Width, request.Height));
+ size = new Size(CollectionView.Frame.Width, request.Height);
+ }
+
+ var platformView = formsElement.ToPlatform();
+ if (platformView.Superview is GeneralWrapperView generalWrapperView)
+ {
+ var originalFrame = generalWrapperView.Frame;
+ generalWrapperView.Frame = new CGRect(originalFrame.X, originalFrame.Y, (nfloat)size.Width, (nfloat)size.Height);
+ }
+ else
+ {
+ var frame = new Rect(platformView.Frame.X, platformView.Frame.Y, size.Width, size.Height);
+ formsElement.Arrange(frame);
+ }
+ }
+
+ void RemeasureLayout(UIView nativeView)
+ {
+ var originalFrame = nativeView.Frame;
+
+ if (IsHorizontal)
+ {
+ var constraints = new CGSize(double.PositiveInfinity, CollectionView.Frame.Height);
+ var size = nativeView.SizeThatFits(constraints);
+ nativeView.Frame = new CGRect(originalFrame.X, originalFrame.Y, size.Width, CollectionView.Frame.Height);
+ }
+ else
+ {
+ var constraints = new CGSize(CollectionView.Frame.Width, double.PositiveInfinity);
+ var size = nativeView.SizeThatFits(constraints);
+ nativeView.Frame = new CGRect(originalFrame.X, originalFrame.Y, CollectionView.Frame.Width, size.Height);
+ }
+ }
+
+ private protected void RemeasureLayout(VisualElement formsElement, UIView nativeElement)
+ {
+ if (formsElement is not null)
+ {
+ RemeasureLayout(formsElement);
+ }
+ else if (nativeElement is not null)
+ {
+ RemeasureLayout(nativeElement);
}
}
@@ -684,7 +765,7 @@ void ShowEmptyView()
ItemsView.AddLogicalChild(_emptyViewFormsElement);
}
- LayoutEmptyView();
+ _emptyUIView.InvalidateMeasure();
AlignEmptyView();
_emptyViewDisplayed = true;
@@ -723,9 +804,7 @@ void LayoutEmptyView()
var frame = DetermineEmptyViewFrame();
_emptyUIView.Frame = frame;
-
- if (_emptyViewFormsElement != null && ((IElementController)ItemsView).LogicalChildren.IndexOf(_emptyViewFormsElement) != -1)
- _emptyViewFormsElement.Layout(frame.ToRectangle());
+ _emptyViewFormsElement?.Arrange(frame.ToRectangle());
}
TemplatedCell CreateAppropriateCellForLayout()
diff --git a/src/Controls/src/Core/Handlers/Items/iOS/StructuredItemsViewController.cs b/src/Controls/src/Core/Handlers/Items/iOS/StructuredItemsViewController.cs
index b92557a09a22..d0bfb95fe55c 100644
--- a/src/Controls/src/Core/Handlers/Items/iOS/StructuredItemsViewController.cs
+++ b/src/Controls/src/Core/Handlers/Items/iOS/StructuredItemsViewController.cs
@@ -74,25 +74,18 @@ protected override CGRect DetermineEmptyViewFrame()
Math.Abs(CollectionView.Frame.Height - (headerHeight + footerHeight)));
}
- public override void ViewWillLayoutSubviews()
+ private protected override void MeasureSupplementaryViews()
{
- var hasHeaderOrFooter = _footerViewFormsElement is not null || _headerViewFormsElement is not null;
- if (hasHeaderOrFooter && CollectionView is MauiCollectionView { NeedsCellLayout: true } collectionView)
- {
- if (_headerViewFormsElement is not null)
- {
- RemeasureLayout(_headerViewFormsElement);
- }
+ base.MeasureSupplementaryViews();
- if (_footerViewFormsElement is not null)
- {
- RemeasureLayout(_footerViewFormsElement);
- }
-
- UpdateHeaderFooterPosition();
- }
+ RemeasureLayout(_headerViewFormsElement, _headerUIView);
+ RemeasureLayout(_footerViewFormsElement, _footerUIView);
+ }
- base.ViewWillLayoutSubviews();
+ private protected override void LayoutSupplementaryViews()
+ {
+ base.LayoutSupplementaryViews();
+ UpdateHeaderFooterPosition();
}
internal void UpdateFooterView()
@@ -131,14 +124,7 @@ internal void UpdateSubview(object view, DataTemplate viewTemplate, nint viewTag
ItemsView.AddLogicalChild(formsElement);
}
- if (formsElement != null)
- {
- RemeasureLayout(formsElement);
- }
- else
- {
- uiView?.SizeToFit();
- }
+ RemeasureLayout(formsElement, uiView);
}
void UpdateHeaderFooterPosition()
@@ -149,22 +135,10 @@ void UpdateHeaderFooterPosition()
{
var currentInset = CollectionView.ContentInset;
- nfloat headerWidth = ((ItemsView?.Header is View) ? _headerViewFormsElement?.ToPlatform() : _headerUIView)?.Frame.Width ?? 0f;
- nfloat footerWidth = ((ItemsView?.Footer is View) ? _footerViewFormsElement?.ToPlatform() : _footerUIView)?.Frame.Width ?? 0f;
+ nfloat headerWidth = _headerUIView?.Frame.Width ?? 0f;
+ nfloat footerWidth = _footerUIView?.Frame.Width ?? 0f;
nfloat emptyWidth = emptyView?.Frame.Width ?? 0f;
- if (_headerUIView != null && _headerUIView.Frame.X != headerWidth)
- {
- _headerUIView.Frame = new CoreGraphics.CGRect(-headerWidth, 0, headerWidth, CollectionView.Frame.Height);
- }
-
- if (_footerUIView != null && (_footerUIView.Frame.X != ItemsViewLayout.CollectionViewContentSize.Width || emptyWidth > 0))
- {
- _footerUIView.Frame = new CoreGraphics.CGRect(
- ItemsViewLayout.CollectionViewContentSize.Width + emptyWidth, 0, footerWidth,
- CollectionView.Frame.Height);
- }
-
if (CollectionView.ContentInset.Left != headerWidth || CollectionView.ContentInset.Right != footerWidth)
{
var currentOffset = CollectionView.ContentOffset;
@@ -177,14 +151,31 @@ void UpdateHeaderFooterPosition()
// if the header grows it will scroll off the screen because if you change the content inset iOS adjusts the content offset so the list doesn't move
// this changes the offset of the list by however much the header size has changed
- CollectionView.ContentOffset = new CoreGraphics.CGPoint(xOffset, CollectionView.ContentOffset.Y);
+ CollectionView.ContentOffset = new CGPoint(xOffset, CollectionView.ContentOffset.Y);
+ }
+
+ if (_headerUIView != null && _headerUIView.Frame.X != -headerWidth)
+ {
+ _headerUIView.Frame = new CGRect(-headerWidth, 0, headerWidth, CollectionView.Frame.Height);
+ }
+
+ if (_footerUIView != null && IsViewLoaded && View.Window != null)
+ {
+ var width = ItemsViewLayout.CollectionViewContentSize.Width;
+ var footerX = width + emptyWidth;
+ var currentFrame = _footerUIView.Frame;
+
+ if (currentFrame.X != footerX)
+ {
+ _footerUIView.Frame = new CGRect(footerX, 0, footerWidth, CollectionView.Frame.Height);
+ }
}
}
else
{
var currentInset = CollectionView.ContentInset;
- nfloat headerHeight = ((ItemsView?.Header is View) ? _headerViewFormsElement?.ToPlatform() : _headerUIView)?.Frame.Height ?? 0f;
- nfloat footerHeight = ((ItemsView?.Footer is View) ? _footerViewFormsElement?.ToPlatform() : _footerUIView)?.Frame.Height ?? 0f;
+ nfloat headerHeight = _headerUIView?.Frame.Height ?? 0f;
+ nfloat footerHeight = _footerUIView?.Frame.Height ?? 0f;
nfloat emptyHeight = emptyView?.Frame.Height ?? 0f;
if (CollectionView.ContentInset.Top != headerHeight || CollectionView.ContentInset.Bottom != footerHeight)
@@ -202,25 +193,25 @@ void UpdateHeaderFooterPosition()
if (currentOffset.Y.Value < headerHeight)
{
- CollectionView.ContentOffset = new CoreGraphics.CGPoint(CollectionView.ContentOffset.X, yOffset);
+ CollectionView.ContentOffset = new CGPoint(CollectionView.ContentOffset.X, yOffset);
}
}
- if (_headerUIView != null && _headerUIView.Frame.Y != headerHeight)
+ if (_headerUIView != null && _headerUIView.Frame.Y != -headerHeight)
{
- _headerUIView.Frame = new CoreGraphics.CGRect(0, -headerHeight, CollectionView.Frame.Width, headerHeight);
+ _headerUIView.Frame = new CGRect(0, -headerHeight, CollectionView.Frame.Width, headerHeight);
}
- nfloat height = 0;
-
- if (IsViewLoaded && View.Window != null)
+ if (_footerUIView != null && IsViewLoaded && View.Window != null)
{
- height = ItemsViewLayout.CollectionViewContentSize.Height;
- }
+ var height = ItemsViewLayout.CollectionViewContentSize.Height;
+ var footerY = height + emptyHeight;
+ var currentFrame = _footerUIView.Frame;
- if (_footerUIView != null && (_footerUIView.Frame.Y != height || emptyHeight > 0 || _footerUIView.Frame.Height != footerHeight))
- {
- _footerUIView.Frame = new CoreGraphics.CGRect(0, height + emptyHeight, CollectionView.Frame.Width, footerHeight);
+ if (currentFrame.Y != footerY)
+ {
+ _footerUIView.Frame = new CGRect(0, footerY, CollectionView.Frame.Width, footerHeight);
+ }
}
}
}
diff --git a/src/Controls/src/Core/Handlers/Items/iOS/TemplatedCell.cs b/src/Controls/src/Core/Handlers/Items/iOS/TemplatedCell.cs
index da66c38015a3..d3c238ec10e4 100644
--- a/src/Controls/src/Core/Handlers/Items/iOS/TemplatedCell.cs
+++ b/src/Controls/src/Core/Handlers/Items/iOS/TemplatedCell.cs
@@ -53,6 +53,7 @@ protected TemplatedCell(CGRect frame) : base(frame)
WeakReference _handler;
bool _measureInvalidated;
+ bool _needsArrange;
internal bool MeasureInvalidated => _measureInvalidated;
@@ -95,38 +96,48 @@ public override UICollectionViewLayoutAttributes PreferredLayoutAttributesFittin
{
var preferredAttributes = base.PreferredLayoutAttributesFittingAttributes(layoutAttributes);
- if (_measureInvalidated || !AttributesConsistentWithConstrainedDimension(preferredAttributes))
+ if (_measureInvalidated ||
+ !AttributesConsistentWithConstrainedDimension(preferredAttributes) ||
+ !preferredAttributes.Frame.Size.IsCloseTo(_size))
{
// Measure this cell (including the Forms element) if there is no constrained size
var size = ConstrainedSize == default ? Measure() : ConstrainedSize;
-
_size = size.ToSize();
+ _needsArrange = true;
_measureInvalidated = false;
+ preferredAttributes.Frame = new CGRect(preferredAttributes.Frame.Location, _size);
+ // Ensure we get a layout pass to arrange the virtual view.
+ // This is not happening sometimes due to the way we update constraints on visible cells.
+ SetNeedsLayout();
+ OnLayoutAttributesChanged(preferredAttributes);
}
- // Adjust the preferred attributes to include space for the Forms element
- preferredAttributes.Frame = new CGRect(preferredAttributes.Frame.Location, _size);
-
- OnLayoutAttributesChanged(preferredAttributes);
-
return preferredAttributes;
}
public override void LayoutSubviews()
{
+ base.LayoutSubviews();
+
if (PlatformHandler?.VirtualView is { } virtualView)
{
- // While the platform view Frame is set via auto-layout constraints,
- // we have to set the Frame on the virtual view manually.
- // Subviews will eventually be arranged via LayoutSubviews once the cell comes into play.
- var frame = new Rect(Point.Zero, Bounds.Size.ToSize());
- if (virtualView.Frame != frame)
+ var boundsSize = Bounds.Size.ToSize();
+ if (!_needsArrange)
{
- virtualView.Arrange(frame);
+ // While rotating the device, and under other circumstances,
+ // a layout pass is being triggered without going through PreferredLayoutAttributesFittingAttributes first.
+ // In this case we should not trigger an Arrange pass because
+ // the last measurement does not match the new bounds size.
+ return;
}
- }
- base.LayoutSubviews();
+ _needsArrange = false;
+
+ // We now have to apply the new bounds size to the virtual view
+ // which will automatically set the frame on the platform view too.
+ var frame = new Rect(Point.Zero, boundsSize);
+ virtualView.Arrange(frame);
+ }
}
[Obsolete]
@@ -203,14 +214,14 @@ public void Bind(DataTemplate template, object bindingContext, ItemsView itemsVi
}
CurrentTemplate = itemTemplate;
- this.UpdateAccessibilityTraits(itemsView);
+ this.UpdateAccessibilityTraits(itemsView);
MarkAsBound();
}
void MarkAsBound()
{
_bound = true;
- ((IPlatformMeasureInvalidationController)this).InvalidateMeasure();
+ this.InvalidateMeasure();
}
void SetRenderer(IPlatformViewHandler renderer)
@@ -222,7 +233,7 @@ void SetRenderer(IPlatformViewHandler renderer)
// Clear out any old views if this cell is being reused
ClearSubviews();
- InitializeContentConstraints(platformView);
+ SetupPlatformView(platformView);
ContentView.MarkAsCrossPlatformLayoutBacking();
UpdateVisualStates();
diff --git a/src/Controls/src/Core/Handlers/Items2/iOS/ItemsViewCell2.cs b/src/Controls/src/Core/Handlers/Items2/iOS/ItemsViewCell2.cs
index 64efc147ee38..a407b43a3388 100644
--- a/src/Controls/src/Core/Handlers/Items2/iOS/ItemsViewCell2.cs
+++ b/src/Controls/src/Core/Handlers/Items2/iOS/ItemsViewCell2.cs
@@ -24,9 +24,13 @@ protected ItemsViewCell2(CGRect frame) : base(frame)
}
protected void InitializeContentConstraints(UIView platformView)
+ {
+ SetupPlatformView(platformView, true);
+ }
+
+ private protected void SetupPlatformView(UIView platformView, bool autoLayout = false)
{
ContentView.TranslatesAutoresizingMaskIntoConstraints = false;
- platformView.TranslatesAutoresizingMaskIntoConstraints = false;
ContentView.AddSubview(platformView);
@@ -36,12 +40,15 @@ protected void InitializeContentConstraints(UIView platformView)
ContentView.LeadingAnchor.ConstraintEqualTo(LeadingAnchor).Active = true;
ContentView.TrailingAnchor.ConstraintEqualTo(TrailingAnchor).Active = true;
- // And we want the ContentView to be the same size as the root renderer for the Forms element
- // TODO: we should probably remove this to support `Margin` applied to the cell's root `VirtualView`
- ContentView.TopAnchor.ConstraintEqualTo(platformView.TopAnchor).Active = true;
- ContentView.BottomAnchor.ConstraintEqualTo(platformView.BottomAnchor).Active = true;
- ContentView.LeadingAnchor.ConstraintEqualTo(platformView.LeadingAnchor).Active = true;
- ContentView.TrailingAnchor.ConstraintEqualTo(platformView.TrailingAnchor).Active = true;
+ if (autoLayout)
+ {
+ // And we want the ContentView to be the same size as the root renderer for the Forms element
+ platformView.TranslatesAutoresizingMaskIntoConstraints = false;
+ ContentView.TopAnchor.ConstraintEqualTo(platformView.TopAnchor).Active = true;
+ ContentView.BottomAnchor.ConstraintEqualTo(platformView.BottomAnchor).Active = true;
+ ContentView.LeadingAnchor.ConstraintEqualTo(platformView.LeadingAnchor).Active = true;
+ ContentView.TrailingAnchor.ConstraintEqualTo(platformView.TrailingAnchor).Active = true;
+ }
}
// public abstract void ConstrainTo(nfloat constant);
diff --git a/src/Controls/src/Core/Handlers/Items2/iOS/TemplatedCell2.cs b/src/Controls/src/Core/Handlers/Items2/iOS/TemplatedCell2.cs
index 75b8eaac9102..16ba34065d9d 100644
--- a/src/Controls/src/Core/Handlers/Items2/iOS/TemplatedCell2.cs
+++ b/src/Controls/src/Core/Handlers/Items2/iOS/TemplatedCell2.cs
@@ -36,6 +36,7 @@ public event EventHandler LayoutAttributesCha
bool _bound;
bool _measureInvalidated;
+ bool _needsArrange;
Size _measuredSize;
Size _cachedConstraints;
@@ -94,6 +95,7 @@ public override UICollectionViewLayoutAttributes PreferredLayoutAttributesFittin
var measure = virtualView.Measure(constraints.Width, constraints.Height);
_cachedConstraints = constraints;
_measuredSize = measure;
+ _needsArrange = true;
}
var size = ScrollDirection == UICollectionViewScrollDirection.Vertical
@@ -111,19 +113,27 @@ public override UICollectionViewLayoutAttributes PreferredLayoutAttributesFittin
public override void LayoutSubviews()
{
+ base.LayoutSubviews();
+
if (PlatformHandler?.VirtualView is { } virtualView)
{
- // While the platform view Frame is set via auto-layout constraints,
- // we have to set the Frame on the virtual view manually.
- // Subviews will eventually be arranged via LayoutSubviews once the cell comes into play.
- var frame = new Rect(Point.Zero, Bounds.Size.ToSize());
- if (virtualView.Frame != frame)
+ var boundsSize = Bounds.Size.ToSize();
+ if (!_needsArrange)
{
- virtualView.Arrange(frame);
+ // While rotating the device, and under other circumstances,
+ // a layout pass is being triggered without going through PreferredLayoutAttributesFittingAttributes first.
+ // In this case we should not trigger an Arrange pass because
+ // the last measurement does not match the new bounds size.
+ return;
}
- }
- base.LayoutSubviews();
+ _needsArrange = false;
+
+ // We now have to apply the new bounds size to the virtual view
+ // which will automatically set the frame on the platform view too.
+ var frame = new Rect(Point.Zero, boundsSize);
+ virtualView.Arrange(frame);
+ }
}
public override void PrepareForReuse()
@@ -162,7 +172,7 @@ void BindVirtualView(View virtualView, object bindingContext, ItemsView itemsVie
}
PlatformHandler = virtualView.Handler as IPlatformViewHandler;
- InitializeContentConstraints(PlatformView);
+ SetupPlatformView(PlatformView, needsContainer);
ContentView.MarkAsCrossPlatformLayoutBacking();
virtualView.BindingContext = bindingContext;
diff --git a/src/Controls/src/Core/InvalidationEventArgs.cs b/src/Controls/src/Core/InvalidationEventArgs.cs
index 701d725c5290..050c7548fd63 100644
--- a/src/Controls/src/Core/InvalidationEventArgs.cs
+++ b/src/Controls/src/Core/InvalidationEventArgs.cs
@@ -10,15 +10,7 @@ public InvalidationEventArgs(InvalidationTrigger trigger)
{
Trigger = trigger;
}
- public InvalidationEventArgs(InvalidationTrigger trigger, int depth) : this(trigger)
- {
- CurrentInvalidationDepth = depth;
- }
-
public InvalidationTrigger Trigger { get; private set; }
-
-
- public int CurrentInvalidationDepth { set; get; }
}
}
\ No newline at end of file
diff --git a/src/Controls/src/Core/LegacyLayouts/Layout.cs b/src/Controls/src/Core/LegacyLayouts/Layout.cs
index 8b9ac2371c06..e02c311f545b 100644
--- a/src/Controls/src/Core/LegacyLayouts/Layout.cs
+++ b/src/Controls/src/Core/LegacyLayouts/Layout.cs
@@ -202,8 +202,12 @@ public override SizeRequest Measure(double widthConstraint, double heightConstra
SizeRequest size = base.Measure(widthConstraint - Padding.HorizontalThickness, heightConstraint - Padding.VerticalThickness, flags);
#pragma warning restore CS0618 // Type or member is obsolete
#pragma warning disable CS0618 // Type or member is obsolete
- return new SizeRequest(new Size(size.Request.Width + Padding.HorizontalThickness, size.Request.Height + Padding.VerticalThickness),
- new Size(size.Minimum.Width + Padding.HorizontalThickness, size.Minimum.Height + Padding.VerticalThickness));
+ var request = new Size(size.Request.Width + Padding.HorizontalThickness, size.Request.Height + Padding.VerticalThickness);
+ var minimum = new Size(size.Minimum.Width + Padding.HorizontalThickness, size.Minimum.Height + Padding.VerticalThickness);
+
+ DesiredSize = request;
+
+ return new SizeRequest(request, minimum);
#pragma warning restore CS0618 // Type or member is obsolete
}
#pragma warning restore CS0672 // Member overrides obsolete member
@@ -320,7 +324,7 @@ public void RaiseChild(View view)
[Obsolete("Use InvalidateMeasure depending on your scenario")]
protected virtual void InvalidateLayout()
{
- _hasDoneLayout = false;
+ SetNeedsLayout();
InvalidateMeasureInternal(InvalidationTrigger.MeasureChanged);
if (!_hasDoneLayout)
{
@@ -328,6 +332,11 @@ protected virtual void InvalidateLayout()
}
}
+ void SetNeedsLayout()
+ {
+ _hasDoneLayout = false;
+ }
+
///
/// Positions and sizes the children of a layout.
///
@@ -341,10 +350,18 @@ protected virtual void InvalidateLayout()
[Obsolete("Use ArrangeOverride")]
protected abstract void LayoutChildren(double x, double y, double width, double height);
- internal override void OnChildMeasureInvalidatedInternal(VisualElement child, InvalidationTrigger trigger, int depth)
+ internal override void OnChildMeasureInvalidated(VisualElement child, InvalidationTrigger trigger)
{
- // TODO: once we remove old Xamarin public signatures we can invoke `OnChildMeasureInvalidated(VisualElement, InvalidationTrigger)` directly
- OnChildMeasureInvalidated(child, new InvalidationEventArgs(trigger, depth));
+ SetNeedsLayout();
+ InvalidateMeasureCache();
+
+ OnChildMeasureInvalidated(child, new InvalidationEventArgs(trigger));
+
+ var propagatedTrigger = GetPropagatedTrigger(trigger);
+ InvokeMeasureInvalidated(propagatedTrigger);
+
+ // Behavior of legacy layouts is to always propagate the measure invalidation to the parent
+ (Parent as VisualElement)?.OnChildMeasureInvalidated(this, propagatedTrigger);
}
///
@@ -356,19 +373,6 @@ internal override void OnChildMeasureInvalidatedInternal(VisualElement child, In
/// This method has a default implementation and application developers must call the base implementation.
protected void OnChildMeasureInvalidated(object sender, EventArgs e)
{
- var depth = 0;
- InvalidationTrigger trigger;
- if (e is InvalidationEventArgs args)
- {
- trigger = args.Trigger;
- depth = args.CurrentInvalidationDepth;
- }
- else
- {
- trigger = InvalidationTrigger.Undefined;
- }
-
- OnChildMeasureInvalidated((VisualElement)sender, trigger, depth);
OnChildMeasureInvalidated();
}
@@ -542,55 +546,6 @@ internal static void LayoutChildIntoBoundingRegion(View child, Rect region, Size
child.Layout(region);
}
- internal virtual void OnChildMeasureInvalidated(VisualElement child, InvalidationTrigger trigger, int depth)
- {
- IReadOnlyList children = LogicalChildrenInternal;
- int count = children.Count;
- for (var index = 0; index < count; index++)
- {
- if (LogicalChildrenInternal[index] is VisualElement v && v.IsVisible && (!v.IsPlatformEnabled || !v.IsPlatformStateConsistent))
- {
- return;
- }
- }
-
- if (child is View view)
- {
- // we can ignore the request if we are either fully constrained or when the size request changes and we were already fully constrained
- if ((trigger == InvalidationTrigger.MeasureChanged && view.Constraint == LayoutConstraint.Fixed) ||
- (trigger == InvalidationTrigger.SizeRequestChanged && view.ComputedConstraint == LayoutConstraint.Fixed))
- {
- return;
- }
- if (trigger == InvalidationTrigger.HorizontalOptionsChanged || trigger == InvalidationTrigger.VerticalOptionsChanged)
- {
- ComputeConstraintForView(view);
- }
- }
-
- InvalidateMeasureLegacy(trigger, depth, int.MaxValue);
- }
-
- // This lets us override the rules for invalidation on MAUI controls that unfortunately still inheirt from the legacy layout
- private protected virtual void InvalidateMeasureLegacy(InvalidationTrigger trigger, int depth, int depthLeveltoInvalidate)
- {
- if (depth <= depthLeveltoInvalidate)
- {
- if (trigger == InvalidationTrigger.RendererReady)
- {
- InvalidateMeasureInternal(new InvalidationEventArgs(InvalidationTrigger.RendererReady, depth));
- }
- else
- {
- InvalidateMeasureInternal(new InvalidationEventArgs(InvalidationTrigger.MeasureChanged, depth));
- }
- }
- else
- {
- FireMeasureChanged(trigger, depth);
- }
- }
-
internal override void OnIsVisibleChanged(bool oldValue, bool newValue)
{
base.OnIsVisibleChanged(oldValue, newValue);
@@ -708,19 +663,6 @@ bool ShouldLayoutChildren()
return true;
}
- protected override void InvalidateMeasureOverride()
- {
- base.InvalidateMeasureOverride();
-
- foreach (var child in ((IElementController)this).LogicalChildren)
- {
- if (child is IView fe)
- {
- fe.InvalidateMeasure();
- }
- }
- }
-
protected override Size ArrangeOverride(Rect bounds)
{
base.ArrangeOverride(bounds);
diff --git a/src/Controls/src/Core/LegacyLayouts/StackLayout.cs b/src/Controls/src/Core/LegacyLayouts/StackLayout.cs
index 146826a97502..3b948478a6a0 100644
--- a/src/Controls/src/Core/LegacyLayouts/StackLayout.cs
+++ b/src/Controls/src/Core/LegacyLayouts/StackLayout.cs
@@ -92,12 +92,18 @@ protected override SizeRequest OnMeasure(double widthConstraint, double heightCo
return result;
}
+ internal override void OnChildMeasureInvalidated(VisualElement child, InvalidationTrigger trigger)
+ {
+ _layoutInformation = new LayoutInformation();
+ base.OnChildMeasureInvalidated(child, trigger);
+ }
+
internal override void ComputeConstraintForView(View view)
{
ComputeConstraintForView(view, false);
}
- internal override void InvalidateMeasureInternal(InvalidationEventArgs trigger)
+ internal override void InvalidateMeasureInternal(InvalidationTrigger trigger)
{
_layoutInformation = new LayoutInformation();
base.InvalidateMeasureInternal(trigger);
diff --git a/src/Controls/src/Core/Page/Page.cs b/src/Controls/src/Core/Page/Page.cs
index 941f47c52dfb..985bc26842cf 100644
--- a/src/Controls/src/Core/Page/Page.cs
+++ b/src/Controls/src/Core/Page/Page.cs
@@ -506,10 +506,11 @@ protected override void OnBindingContextChanged()
}
- internal override void OnChildMeasureInvalidatedInternal(VisualElement child, InvalidationTrigger trigger, int depth)
+ internal override void OnChildMeasureInvalidated(VisualElement child, InvalidationTrigger trigger)
{
- // TODO: once we remove old Xamarin public signatures we can invoke `OnChildMeasureInvalidated(VisualElement, InvalidationTrigger)` directly
- OnChildMeasureInvalidated(child, new InvalidationEventArgs(trigger, depth));
+ OnChildMeasureInvalidated(child, new InvalidationEventArgs(trigger));
+ var propagatedTrigger = GetPropagatedTrigger(trigger);
+ InvokeMeasureInvalidated(propagatedTrigger);
}
///
@@ -519,19 +520,6 @@ internal override void OnChildMeasureInvalidatedInternal(VisualElement child, In
/// The event arguments.
protected virtual void OnChildMeasureInvalidated(object sender, EventArgs e)
{
- var depth = 0;
- InvalidationTrigger trigger;
- if (e is InvalidationEventArgs args)
- {
- trigger = args.Trigger;
- depth = args.CurrentInvalidationDepth;
- }
- else
- {
- trigger = InvalidationTrigger.Undefined;
- }
-
- OnChildMeasureInvalidated((VisualElement)sender, trigger, depth);
}
///
@@ -610,36 +598,6 @@ protected void UpdateChildrenLayout()
}
}
- internal virtual void OnChildMeasureInvalidated(VisualElement child, InvalidationTrigger trigger, int depth)
- {
- var container = this as IPageContainer;
- if (container != null)
- {
- Page page = container.CurrentPage;
- if (page != null && page.IsVisible && (!page.IsPlatformEnabled || !page.IsPlatformStateConsistent))
- return;
- }
- else
- {
- var logicalChildren = this.InternalChildren;
- for (var i = 0; i < logicalChildren.Count; i++)
- {
- var v = logicalChildren[i] as VisualElement;
- if (v != null && v.IsVisible && (!v.IsPlatformEnabled || !v.IsPlatformStateConsistent))
- return;
- }
- }
-
- if (depth <= 1)
- {
- InvalidateMeasureInternal(new InvalidationEventArgs(InvalidationTrigger.MeasureChanged, depth));
- }
- else
- {
- FireMeasureChanged(trigger, depth);
- }
- }
-
internal void OnAppearing(Action action)
{
if (_hasAppeared)
diff --git a/src/Controls/src/Core/Platform/Android/Extensions/SemanticExtensions.cs b/src/Controls/src/Core/Platform/Android/Extensions/SemanticExtensions.cs
index e285441cccca..2c27f1ef83ea 100644
--- a/src/Controls/src/Core/Platform/Android/Extensions/SemanticExtensions.cs
+++ b/src/Controls/src/Core/Platform/Android/Extensions/SemanticExtensions.cs
@@ -11,16 +11,8 @@ public static void UpdateSemanticNodeInfo(this View virtualView, AccessibilityNo
if (info == null)
return;
- if (virtualView.TapGestureRecognizerNeedsActionClick())
- {
- // Add "double tap to activate" to the screen reader
+ if (virtualView.TapGestureRecognizerNeedsDelegate())
info.AddAction(AccessibilityNodeInfoCompat.AccessibilityActionCompat.ActionClick);
- }
- if (virtualView.TapGestureRecognizerNeedsButtonAnnouncement())
- {
- // Add "button" to the screen reader
- info.ClassName = "android.widget.Button";
- }
}
internal static void AddOrRemoveControlsAccessibilityDelegate(this View virtualView)
diff --git a/src/Controls/src/Core/Platform/SemanticExtensions.cs b/src/Controls/src/Core/Platform/SemanticExtensions.cs
index fec828e62e2f..1a1e7591ea64 100644
--- a/src/Controls/src/Core/Platform/SemanticExtensions.cs
+++ b/src/Controls/src/Core/Platform/SemanticExtensions.cs
@@ -6,9 +6,6 @@ internal static bool ControlsAccessibilityDelegateNeeded(this View virtualView)
=> virtualView.TapGestureRecognizerNeedsDelegate();
internal static bool TapGestureRecognizerNeedsDelegate(this View virtualView)
- => virtualView.TapGestureRecognizerNeedsButtonAnnouncement();
-
- internal static bool TapGestureRecognizerNeedsActionClick(this View virtualView)
{
foreach (var gesture in virtualView.GestureRecognizers)
{
@@ -20,17 +17,5 @@ internal static bool TapGestureRecognizerNeedsActionClick(this View virtualView)
}
return false;
}
-
- internal static bool TapGestureRecognizerNeedsButtonAnnouncement(this View virtualView)
- {
- foreach (var gesture in virtualView.GestureRecognizers)
- {
- if (gesture is TapGestureRecognizer)
- {
- return true;
- }
- }
- return false;
- }
}
}
diff --git a/src/Controls/src/Core/PublicAPI/net-android/PublicAPI.Unshipped.txt b/src/Controls/src/Core/PublicAPI/net-android/PublicAPI.Unshipped.txt
index f48b2b26b2c2..5b8f9021d63e 100644
--- a/src/Controls/src/Core/PublicAPI/net-android/PublicAPI.Unshipped.txt
+++ b/src/Controls/src/Core/PublicAPI/net-android/PublicAPI.Unshipped.txt
@@ -69,6 +69,7 @@ const Microsoft.Maui.Controls.TitleBar.TrailingHiddenState = "TrailingContentCol
const Microsoft.Maui.Controls.TitleBar.TrailingVisibleState = "TrailingContentVisible" -> string!
Microsoft.Maui.Controls.Embedding.EmbeddingExtensions
Microsoft.Maui.Controls.HandlerProperties
+*REMOVED*override Microsoft.Maui.Controls.Compatibility.Layout.InvalidateMeasureOverride() -> void
Microsoft.Maui.Controls.HybridWebView
Microsoft.Maui.Controls.HybridWebView.DefaultFile.get -> string?
Microsoft.Maui.Controls.HybridWebView.DefaultFile.set -> void
diff --git a/src/Controls/src/Core/PublicAPI/net-ios/PublicAPI.Unshipped.txt b/src/Controls/src/Core/PublicAPI/net-ios/PublicAPI.Unshipped.txt
index 63a6c7ddd87a..e33dcb76f5a2 100644
--- a/src/Controls/src/Core/PublicAPI/net-ios/PublicAPI.Unshipped.txt
+++ b/src/Controls/src/Core/PublicAPI/net-ios/PublicAPI.Unshipped.txt
@@ -5,6 +5,7 @@ override Microsoft.Maui.Controls.Handlers.Items2.TemplatedCell2.LayoutSubviews()
override Microsoft.Maui.Controls.Handlers.Items2.ItemsViewHandler2.GetDesiredSize(double widthConstraint, double heightConstraint) -> Microsoft.Maui.Graphics.Size
~abstract Microsoft.Maui.Controls.Handlers.Items2.ItemsViewHandler2.CreateController(TItemsView newElement, UIKit.UICollectionViewLayout layout) -> Microsoft.Maui.Controls.Handlers.Items2.ItemsViewController2
~abstract Microsoft.Maui.Controls.Handlers.Items2.ItemsViewHandler2.SelectLayout() -> UIKit.UICollectionViewLayout
+*REMOVED*override Microsoft.Maui.Controls.Handlers.Items.StructuredItemsViewController.ViewWillLayoutSubviews() -> void
*REMOVED*~Microsoft.Maui.Controls.Handlers.Compatibility.ShellScrollViewTracker.ShellScrollViewTracker(Microsoft.Maui.IPlatformViewHandler renderer) -> void
~Microsoft.Maui.Controls.Handlers.Items2.CarouselViewController2.CarouselViewController2(Microsoft.Maui.Controls.CarouselView itemsView, UIKit.UICollectionViewLayout layout) -> void
~Microsoft.Maui.Controls.Handlers.Items2.CarouselViewDelegator2.CarouselViewDelegator2(UIKit.UICollectionViewLayout itemsViewLayout, Microsoft.Maui.Controls.Handlers.Items2.CarouselViewController2 ItemsViewController2) -> void
@@ -205,6 +206,7 @@ const Microsoft.Maui.Controls.TitleBar.TrailingHiddenState = "TrailingContentCol
const Microsoft.Maui.Controls.TitleBar.TrailingVisibleState = "TrailingContentVisible" -> string!
Microsoft.Maui.Controls.Embedding.EmbeddingExtensions
Microsoft.Maui.Controls.HandlerProperties
+*REMOVED*override Microsoft.Maui.Controls.Compatibility.Layout.InvalidateMeasureOverride() -> void
*REMOVED*Microsoft.Maui.Controls.Handlers.Compatibility.ShellScrollViewTracker
*REMOVED*Microsoft.Maui.Controls.Handlers.Compatibility.ShellScrollViewTracker.Dispose() -> void
*REMOVED*Microsoft.Maui.Controls.Handlers.Compatibility.ShellScrollViewTracker.OnLayoutSubviews() -> void
diff --git a/src/Controls/src/Core/PublicAPI/net-maccatalyst/PublicAPI.Unshipped.txt b/src/Controls/src/Core/PublicAPI/net-maccatalyst/PublicAPI.Unshipped.txt
index 4d313d1b0c85..6950a4815676 100644
--- a/src/Controls/src/Core/PublicAPI/net-maccatalyst/PublicAPI.Unshipped.txt
+++ b/src/Controls/src/Core/PublicAPI/net-maccatalyst/PublicAPI.Unshipped.txt
@@ -5,6 +5,7 @@ override Microsoft.Maui.Controls.Handlers.Items2.TemplatedCell2.LayoutSubviews()
override Microsoft.Maui.Controls.Handlers.Items2.ItemsViewHandler2.GetDesiredSize(double widthConstraint, double heightConstraint) -> Microsoft.Maui.Graphics.Size
~abstract Microsoft.Maui.Controls.Handlers.Items2.ItemsViewHandler2.CreateController(TItemsView newElement, UIKit.UICollectionViewLayout layout) -> Microsoft.Maui.Controls.Handlers.Items2.ItemsViewController2
~abstract Microsoft.Maui.Controls.Handlers.Items2.ItemsViewHandler2.SelectLayout() -> UIKit.UICollectionViewLayout
+*REMOVED*override Microsoft.Maui.Controls.Handlers.Items.StructuredItemsViewController.ViewWillLayoutSubviews() -> void
*REMOVED*~Microsoft.Maui.Controls.Handlers.Compatibility.ShellScrollViewTracker.ShellScrollViewTracker(Microsoft.Maui.IPlatformViewHandler renderer) -> void
~Microsoft.Maui.Controls.Handlers.Items2.CarouselViewController2.CarouselViewController2(Microsoft.Maui.Controls.CarouselView itemsView, UIKit.UICollectionViewLayout layout) -> void
~Microsoft.Maui.Controls.Handlers.Items2.CarouselViewDelegator2.CarouselViewDelegator2(UIKit.UICollectionViewLayout itemsViewLayout, Microsoft.Maui.Controls.Handlers.Items2.CarouselViewController2 ItemsViewController2) -> void
@@ -206,6 +207,7 @@ const Microsoft.Maui.Controls.TitleBar.TrailingHiddenState = "TrailingContentCol
const Microsoft.Maui.Controls.TitleBar.TrailingVisibleState = "TrailingContentVisible" -> string!
Microsoft.Maui.Controls.Embedding.EmbeddingExtensions
Microsoft.Maui.Controls.HandlerProperties
+*REMOVED*override Microsoft.Maui.Controls.Compatibility.Layout.InvalidateMeasureOverride() -> void
*REMOVED*Microsoft.Maui.Controls.Handlers.Compatibility.ShellScrollViewTracker
*REMOVED*Microsoft.Maui.Controls.Handlers.Compatibility.ShellScrollViewTracker.Dispose() -> void
*REMOVED*Microsoft.Maui.Controls.Handlers.Compatibility.ShellScrollViewTracker.OnLayoutSubviews() -> void
diff --git a/src/Controls/src/Core/PublicAPI/net-tizen/PublicAPI.Unshipped.txt b/src/Controls/src/Core/PublicAPI/net-tizen/PublicAPI.Unshipped.txt
index 275b44d25503..4ee051439ef7 100644
--- a/src/Controls/src/Core/PublicAPI/net-tizen/PublicAPI.Unshipped.txt
+++ b/src/Controls/src/Core/PublicAPI/net-tizen/PublicAPI.Unshipped.txt
@@ -68,6 +68,7 @@ const Microsoft.Maui.Controls.TitleBar.TitleVisibleState = "TitleVisible" -> str
const Microsoft.Maui.Controls.TitleBar.TrailingHiddenState = "TrailingContentCollapsed" -> string!
const Microsoft.Maui.Controls.TitleBar.TrailingVisibleState = "TrailingContentVisible" -> string!
Microsoft.Maui.Controls.HandlerProperties
+*REMOVED*override Microsoft.Maui.Controls.Compatibility.Layout.InvalidateMeasureOverride() -> void
Microsoft.Maui.Controls.HybridWebView
Microsoft.Maui.Controls.HybridWebView.DefaultFile.get -> string?
Microsoft.Maui.Controls.HybridWebView.DefaultFile.set -> void
diff --git a/src/Controls/src/Core/PublicAPI/net-windows/PublicAPI.Unshipped.txt b/src/Controls/src/Core/PublicAPI/net-windows/PublicAPI.Unshipped.txt
index b1dbe9d0aa07..c2190ccab4e5 100644
--- a/src/Controls/src/Core/PublicAPI/net-windows/PublicAPI.Unshipped.txt
+++ b/src/Controls/src/Core/PublicAPI/net-windows/PublicAPI.Unshipped.txt
@@ -70,6 +70,7 @@ const Microsoft.Maui.Controls.TitleBar.TrailingHiddenState = "TrailingContentCol
const Microsoft.Maui.Controls.TitleBar.TrailingVisibleState = "TrailingContentVisible" -> string!
Microsoft.Maui.Controls.Embedding.EmbeddingExtensions
Microsoft.Maui.Controls.HandlerProperties
+*REMOVED*override Microsoft.Maui.Controls.Compatibility.Layout.InvalidateMeasureOverride() -> void
Microsoft.Maui.Controls.HybridWebView
Microsoft.Maui.Controls.HybridWebView.DefaultFile.get -> string?
Microsoft.Maui.Controls.HybridWebView.DefaultFile.set -> void
diff --git a/src/Controls/src/Core/PublicAPI/net/PublicAPI.Unshipped.txt b/src/Controls/src/Core/PublicAPI/net/PublicAPI.Unshipped.txt
index 27745f220371..0950e21053b6 100644
--- a/src/Controls/src/Core/PublicAPI/net/PublicAPI.Unshipped.txt
+++ b/src/Controls/src/Core/PublicAPI/net/PublicAPI.Unshipped.txt
@@ -68,6 +68,7 @@ const Microsoft.Maui.Controls.TitleBar.TitleVisibleState = "TitleVisible" -> str
const Microsoft.Maui.Controls.TitleBar.TrailingHiddenState = "TrailingContentCollapsed" -> string!
const Microsoft.Maui.Controls.TitleBar.TrailingVisibleState = "TrailingContentVisible" -> string!
Microsoft.Maui.Controls.HandlerProperties
+*REMOVED*override Microsoft.Maui.Controls.Compatibility.Layout.InvalidateMeasureOverride() -> void
Microsoft.Maui.Controls.HybridWebView
Microsoft.Maui.Controls.HybridWebView.DefaultFile.get -> string?
Microsoft.Maui.Controls.HybridWebView.DefaultFile.set -> void
diff --git a/src/Controls/src/Core/PublicAPI/netstandard/PublicAPI.Unshipped.txt b/src/Controls/src/Core/PublicAPI/netstandard/PublicAPI.Unshipped.txt
index 275b44d25503..4ee051439ef7 100644
--- a/src/Controls/src/Core/PublicAPI/netstandard/PublicAPI.Unshipped.txt
+++ b/src/Controls/src/Core/PublicAPI/netstandard/PublicAPI.Unshipped.txt
@@ -68,6 +68,7 @@ const Microsoft.Maui.Controls.TitleBar.TitleVisibleState = "TitleVisible" -> str
const Microsoft.Maui.Controls.TitleBar.TrailingHiddenState = "TrailingContentCollapsed" -> string!
const Microsoft.Maui.Controls.TitleBar.TrailingVisibleState = "TrailingContentVisible" -> string!
Microsoft.Maui.Controls.HandlerProperties
+*REMOVED*override Microsoft.Maui.Controls.Compatibility.Layout.InvalidateMeasureOverride() -> void
Microsoft.Maui.Controls.HybridWebView
Microsoft.Maui.Controls.HybridWebView.DefaultFile.get -> string?
Microsoft.Maui.Controls.HybridWebView.DefaultFile.set -> void
diff --git a/src/Controls/src/Core/ScrollView/ScrollView.cs b/src/Controls/src/Core/ScrollView/ScrollView.cs
index 23489e87fb54..7c226a3b7565 100644
--- a/src/Controls/src/Core/ScrollView/ScrollView.cs
+++ b/src/Controls/src/Core/ScrollView/ScrollView.cs
@@ -478,11 +478,6 @@ Size ICrossPlatformLayout.CrossPlatformArrange(Rect bounds)
return bounds.Size;
}
- private protected override void InvalidateMeasureLegacy(InvalidationTrigger trigger, int depth, int depthLeveltoInvalidate)
- {
- base.InvalidateMeasureLegacy(trigger, depth, 1);
- }
-
private protected override string GetDebuggerDisplay()
{
var debugText = DebuggerDisplayHelpers.GetDebugText(nameof(Content), Content);
diff --git a/src/Controls/src/Core/TemplatedView/TemplatedView.cs b/src/Controls/src/Core/TemplatedView/TemplatedView.cs
index 23ef916eafbd..3e8cd53943bf 100644
--- a/src/Controls/src/Core/TemplatedView/TemplatedView.cs
+++ b/src/Controls/src/Core/TemplatedView/TemplatedView.cs
@@ -150,11 +150,6 @@ Size ICrossPlatformLayout.CrossPlatformArrange(Rect bounds)
return bounds.Size;
}
- private protected override void InvalidateMeasureLegacy(InvalidationTrigger trigger, int depth, int depthLeveltoInvalidate)
- {
- base.InvalidateMeasureLegacy(trigger, depth, 1);
- }
-
#nullable disable
}
diff --git a/src/Controls/src/Core/VisualElement/VisualElement.cs b/src/Controls/src/Core/VisualElement/VisualElement.cs
index 6161fcd8a8c1..c392162019ce 100644
--- a/src/Controls/src/Core/VisualElement/VisualElement.cs
+++ b/src/Controls/src/Core/VisualElement/VisualElement.cs
@@ -269,12 +269,9 @@ static void OnTransformChanged(BindableObject bindable, object oldValue, object
BindableProperty.Create("TransformOrigin", typeof(Point), typeof(VisualElement), new Point(.5d, .5d),
propertyChanged: (b, o, n) => { (((VisualElement)b).AnchorX, ((VisualElement)b).AnchorY) = (Point)n; });
- bool _isVisibleExplicit = (bool)IsVisibleProperty.DefaultValue;
-
/// Bindable property for .
public static readonly BindableProperty IsVisibleProperty = BindableProperty.Create(nameof(IsVisible), typeof(bool), typeof(VisualElement), true,
- propertyChanged: (bindable, oldvalue, newvalue) => ((VisualElement)bindable).OnIsVisibleChanged((bool)oldvalue, (bool)newvalue),
- coerceValue: CoerceIsVisibleProperty);
+ propertyChanged: (bindable, oldvalue, newvalue) => ((VisualElement)bindable).OnIsVisibleChanged((bool)oldvalue, (bool)newvalue));
/// Bindable property for .
public static readonly BindableProperty OpacityProperty = BindableProperty.Create(nameof(Opacity), typeof(double), typeof(VisualElement), 1d, coerceValue: (bindable, value) => ((double)value).Clamp(0, 1));
@@ -697,36 +694,6 @@ private protected bool InputTransparentCore
}
}
- ///
- /// This value represents the cumulative IsVisible value.
- /// All types that override this property need to also invoke
- /// the RefreshIsVisibleProperty() method if the value will change.
- ///
- private protected bool IsVisibleCore
- {
- get
- {
- if (_isVisibleExplicit == false)
- {
- // If the explicitly set value is false, then nothing else matters
- // And we can save the effort of a Parent check
- return false;
- }
-
- var parent = Parent as VisualElement;
- while (parent is not null)
- {
- if (!parent.IsVisible)
- {
- return false;
- }
- parent = parent.Parent as VisualElement;
- }
-
- return _isVisibleExplicit;
- }
- }
-
///
/// Gets a value indicating whether this element is focused currently. This is a bindable property.
///
@@ -1384,6 +1351,7 @@ internal void ComputeConstrainsForChildren()
}
}
+ // TODO: .NET10 this should be made public so whoever implements a custom layout can leverage this
internal virtual void ComputeConstraintForView(View view) => view.ComputedConstraint = LayoutConstraint.None;
///
@@ -1408,23 +1376,25 @@ public void InvalidateMeasureNonVirtual(InvalidationTrigger trigger)
InvalidateMeasureInternal(trigger);
}
- internal void InvalidateMeasureInternal(InvalidationTrigger trigger)
+ internal virtual void InvalidateMeasureInternal(InvalidationTrigger trigger)
{
- InvalidateMeasureInternal(new InvalidationEventArgs(trigger, 0));
- }
+ InvalidateMeasureCache();
- internal virtual void InvalidateMeasureInternal(InvalidationEventArgs eventArgs)
- {
- _measureCache.Clear();
-
- // TODO ezhart Once we get InvalidateArrange sorted, HorizontalOptionsChanged and
- // VerticalOptionsChanged will need to call ParentView.InvalidateArrange() instead
- switch (eventArgs.Trigger)
+ switch (trigger)
{
case InvalidationTrigger.MarginChanged:
+ ParentView?.InvalidateMeasure();
+ break;
case InvalidationTrigger.HorizontalOptionsChanged:
case InvalidationTrigger.VerticalOptionsChanged:
+ if (this is View thisView && Parent is VisualElement visualParent)
+ {
+ visualParent.ComputeConstraintForView(thisView);
+ }
+
+ // TODO ezhart Once we get InvalidateArrange sorted, HorizontalOptionsChanged and
+ // VerticalOptionsChanged will need to call ParentView.InvalidateArrange() instead
ParentView?.InvalidateMeasure();
break;
default:
@@ -1432,50 +1402,47 @@ internal virtual void InvalidateMeasureInternal(InvalidationEventArgs eventArgs)
break;
}
- FireMeasureChanged(eventArgs);
+ InvokeMeasureInvalidated(trigger);
+#pragma warning disable CS0618 // Type or member is obsolete
+ (Parent as VisualElement)?.OnChildMeasureInvalidated(this, trigger);
+#pragma warning restore CS0618 // Type or member is obsolete
}
- private protected void FireMeasureChanged(InvalidationTrigger trigger, int depth)
+ private protected void InvokeMeasureInvalidated(InvalidationTrigger trigger)
{
- FireMeasureChanged(new InvalidationEventArgs(trigger, depth));
+ MeasureInvalidated?.Invoke(this, new InvalidationEventArgs(trigger));
}
+ ///
+ /// A flag that determines whether the measure invalidated event should not be propagated up the visual tree.
+ ///
+ ///
+ /// Propagation will still occur within legacy layout subtrees.
+ ///
+ internal static bool SkipMeasureInvalidatedPropagation { get; set /* for testing purpose */; } =
+ AppContext.TryGetSwitch("Microsoft.Maui.RuntimeFeature.SkipMeasureInvalidatedPropagation", out var enabled) && enabled;
- private protected void FireMeasureChanged(InvalidationEventArgs args)
+ internal virtual void OnChildMeasureInvalidated(VisualElement child, InvalidationTrigger trigger)
{
- var depth = args.CurrentInvalidationDepth;
- MeasureInvalidated?.Invoke(this, args);
- (Parent as VisualElement)?.OnChildMeasureInvalidatedInternal(this, args.Trigger, ++depth);
+ if (SkipMeasureInvalidatedPropagation)
+ {
+ return;
+ }
+
+ var propagatedTrigger = GetPropagatedTrigger(trigger);
+ InvokeMeasureInvalidated(propagatedTrigger);
+ (Parent as VisualElement)?.OnChildMeasureInvalidated(this, propagatedTrigger);
}
- // We don't want to change the execution path of Page or Layout when they are calling "InvalidationMeasure"
- // If you look at page it calls OnChildMeasureInvalidated from OnChildMeasureInvalidatedInternal
- // Because OnChildMeasureInvalidated is public API and the user might override it, we need to keep it as is
- //private protected int CurrentInvalidationDepth { get; set; }
+ private protected static InvalidationTrigger GetPropagatedTrigger(InvalidationTrigger trigger)
+ {
+ var propagatedTrigger = trigger == InvalidationTrigger.RendererReady ? trigger : InvalidationTrigger.MeasureChanged;
+ return propagatedTrigger;
+ }
- internal virtual void OnChildMeasureInvalidatedInternal(VisualElement child, InvalidationTrigger trigger, int depth)
+ private protected void InvalidateMeasureCache()
{
- switch (trigger)
- {
- case InvalidationTrigger.VerticalOptionsChanged:
- case InvalidationTrigger.HorizontalOptionsChanged:
- // When a child changes its HorizontalOptions or VerticalOptions
- // the size of the parent won't change, so we don't have to invalidate the measure
- return;
- case InvalidationTrigger.RendererReady:
- // Undefined happens in many cases, including when `IsVisible` changes
- case InvalidationTrigger.Undefined:
- FireMeasureChanged(trigger, depth);
- return;
- default:
- // When visibility changes `InvalidationTrigger.Undefined` is used,
- // so here we're sure that visibility didn't change
- if (child.IsVisible)
- {
- FireMeasureChanged(InvalidationTrigger.MeasureChanged, depth);
- }
- return;
- }
+ _measureCache.Clear();
}
///
@@ -1532,7 +1499,6 @@ internal virtual void OnIsVisibleChanged(bool oldValue, bool newValue)
fe.Handler?.UpdateValue(nameof(IView.Visibility));
}
- (this as IPropertyPropagationController)?.PropagatePropertyChanged(IsVisibleProperty.PropertyName);
InvalidateMeasureInternal(InvalidationTrigger.Undefined);
}
@@ -1697,17 +1663,6 @@ static object CoerceInputTransparentProperty(BindableObject bindable, object val
return false;
}
- static object CoerceIsVisibleProperty(BindableObject bindable, object value)
- {
- if (bindable is VisualElement visualElement)
- {
- visualElement._isVisibleExplicit = (bool)value;
- return visualElement.IsVisibleCore;
- }
-
- return false;
- }
-
static void OnInputTransparentPropertyChanged(BindableObject bindable, object oldValue, object newValue)
{
(bindable as IPropertyPropagationController)?.PropagatePropertyChanged(VisualElement.InputTransparentProperty.PropertyName);
@@ -1775,9 +1730,6 @@ void IPropertyPropagationController.PropagatePropertyChanged(string propertyName
if (propertyName == null || propertyName == InputTransparentProperty.PropertyName)
this.RefreshPropertyValue(InputTransparentProperty, _inputTransparentExplicit);
- if (propertyName == null || propertyName == IsVisibleProperty.PropertyName)
- this.RefreshPropertyValue(IsVisibleProperty, _isVisibleExplicit);
-
PropertyPropagationExtensions.PropagatePropertyChanged(propertyName, this, ((IVisualTreeElement)this).GetVisualChildren());
}
@@ -1788,13 +1740,6 @@ void IPropertyPropagationController.PropagatePropertyChanged(string propertyName
protected void RefreshIsEnabledProperty() =>
this.RefreshPropertyValue(IsEnabledProperty, _isEnabledExplicit);
- ///
- /// This method must always be called if some event occurs and the value of
- /// the property will change.
- ///
- internal void RefreshIsVisibleProperty() =>
- this.RefreshPropertyValue(IsVisibleProperty, _isVisibleExplicit);
-
///
/// This method must always be called if some event occurs and the value of
/// the InputTransparentCore property will change.
diff --git a/src/Controls/tests/Core.UnitTests/PageTests.cs b/src/Controls/tests/Core.UnitTests/PageTests.cs
index 7c530229ec8f..22b758d94205 100644
--- a/src/Controls/tests/Core.UnitTests/PageTests.cs
+++ b/src/Controls/tests/Core.UnitTests/PageTests.cs
@@ -567,16 +567,16 @@ public void LogicalChildrenDontAddToPagesInternalChildren()
}
[Fact]
- public void MeasureInvalidatedPropagatesUpTree()
+ public void MeasureInvalidatedPropagatesUpTreeWithCompatibilityLayouts()
{
- var label = new Label()
+ var label = new LabelInvalidateMeasureCheck
{
IsPlatformEnabled = true
};
- var scrollView = new ScrollViewInvalidationMeasureCheck()
+ var scrollView = new ScrollViewInvalidationMeasureCheck
{
- Content = new VerticalStackLayout()
+ Content = new Compatibility.StackLayout
{
Children = { new ContentView { Content = label, IsPlatformEnabled = true } },
IsPlatformEnabled = true
@@ -584,74 +584,171 @@ public void MeasureInvalidatedPropagatesUpTree()
IsPlatformEnabled = true
};
- var page = new InvalidatePageInvalidateMeasureCheck()
+ var page = new InvalidatePageInvalidateMeasureCheck
{
Content = scrollView
};
- var window = new TestWindow(page);
-
- int fired = 0;
- page.MeasureInvalidated += (sender, args) =>
- {
- fired++;
- };
+ // Set up the window
+ _ = new TestWindow(page);
+ // Reset counters
+ label.InvalidateMeasureCount = 0;
+ label.PlatformInvalidateMeasureCount = 0;
page.InvalidateMeasureCount = 0;
+ page.PlatformInvalidateMeasureCount = 0;
scrollView.InvalidateMeasureCount = 0;
+ scrollView.PlatformInvalidateMeasureCount = 0;
+
+ // Invalidate the label
label.InvalidateMeasureInternal(InvalidationTrigger.MeasureChanged);
- Assert.Equal(1, fired);
- Assert.Equal(0, page.InvalidateMeasureCount);
- Assert.Equal(0, scrollView.InvalidateMeasureCount);
- page.Content.InvalidateMeasureInternal(InvalidationTrigger.MeasureChanged);
+ Assert.Equal(1, label.InvalidateMeasureCount);
+ Assert.Equal(1, label.PlatformInvalidateMeasureCount);
Assert.Equal(1, page.InvalidateMeasureCount);
+ Assert.Equal(0, page.PlatformInvalidateMeasureCount);
+ Assert.Equal(1, scrollView.InvalidateMeasureCount);
+ Assert.Equal(0, scrollView.PlatformInvalidateMeasureCount);
+
+ // Invalidate page content
+ page.Content.InvalidateMeasureInternal(InvalidationTrigger.MeasureChanged);
+ Assert.Equal(2, page.InvalidateMeasureCount);
+ Assert.Equal(0, page.PlatformInvalidateMeasureCount);
+ }
+
+ [Theory]
+ [InlineData(true, 0)]
+ [InlineData(false, 1)]
+ public void MeasureInvalidatedPropagatesUpTreeOnAppSwitch(bool skipMeasureInvalidatedPropagation, int expectedAncestorMeasureInvalidatedEvents)
+ {
+ try
+ {
+ VisualElement.SkipMeasureInvalidatedPropagation = skipMeasureInvalidatedPropagation;
+
+ var label = new LabelInvalidateMeasureCheck { IsPlatformEnabled = true };
+
+ var contentView = new ContentViewInvalidationMeasureCheck { Content = label, IsPlatformEnabled = true };
+
+ var scrollView = new ScrollViewInvalidationMeasureCheck
+ {
+ // VerticalStackLayout is not a CompatibilityLayout so it will not propagate the MeasureInvalidated
+ // event up the tree unless VisualElement.IsMeasureInvalidatedPropagationEnabled switch is set to true
+ Content = new VerticalStackLayout
+ {
+ Children = { contentView },
+ IsPlatformEnabled = true
+ },
+ IsPlatformEnabled = true
+ };
+
+ var page = new InvalidatePageInvalidateMeasureCheck { Content = scrollView };
+
+ // Set up the window
+ _ = new TestWindow(page);
+
+ // Reset counters
+ label.InvalidateMeasureCount = 0;
+ label.PlatformInvalidateMeasureCount = 0;
+ contentView.InvalidateMeasureCount = 0;
+ contentView.PlatformInvalidateMeasureCount = 0;
+ scrollView.InvalidateMeasureCount = 0;
+ scrollView.PlatformInvalidateMeasureCount = 0;
+ page.InvalidateMeasureCount = 0;
+ page.PlatformInvalidateMeasureCount = 0;
+
+ // Invalidate the label
+ label.InvalidateMeasureInternal(InvalidationTrigger.MeasureChanged);
+ Assert.Equal(1, label.InvalidateMeasureCount);
+ Assert.Equal(1, label.PlatformInvalidateMeasureCount);
+ Assert.Equal(1, contentView.InvalidateMeasureCount);
+ Assert.Equal(0, contentView.PlatformInvalidateMeasureCount);
+ Assert.Equal(expectedAncestorMeasureInvalidatedEvents, scrollView.InvalidateMeasureCount);
+ Assert.Equal(0, scrollView.PlatformInvalidateMeasureCount);
+ Assert.Equal(expectedAncestorMeasureInvalidatedEvents, page.InvalidateMeasureCount);
+ Assert.Equal(0, page.PlatformInvalidateMeasureCount);
+ }
+ finally
+ {
+ VisualElement.SkipMeasureInvalidatedPropagation = false;
+ }
}
class LabelInvalidateMeasureCheck : Label
{
+ public int PlatformInvalidateMeasureCount { get; set; }
public int InvalidateMeasureCount { get; set; }
public LabelInvalidateMeasureCheck()
{
+ MeasureInvalidated += (sender, args) =>
+ {
+ InvalidateMeasureCount++;
+ };
+ }
+
+ internal override void InvalidateMeasureInternal(InvalidationTrigger trigger)
+ {
+ base.InvalidateMeasureInternal(trigger);
+ PlatformInvalidateMeasureCount++;
+ }
+ }
+ class ContentViewInvalidationMeasureCheck : ContentView
+ {
+ public int PlatformInvalidateMeasureCount { get; set; }
+ public int InvalidateMeasureCount { get; set; }
+
+ public ContentViewInvalidationMeasureCheck()
+ {
+ MeasureInvalidated += (sender, args) =>
+ {
+ InvalidateMeasureCount++;
+ };
}
- internal override void InvalidateMeasureInternal(InvalidationEventArgs trigger)
+ internal override void InvalidateMeasureInternal(InvalidationTrigger trigger)
{
base.InvalidateMeasureInternal(trigger);
- InvalidateMeasureCount++;
+ PlatformInvalidateMeasureCount++;
}
}
class ScrollViewInvalidationMeasureCheck : ScrollView
{
+ public int PlatformInvalidateMeasureCount { get; set; }
public int InvalidateMeasureCount { get; set; }
public ScrollViewInvalidationMeasureCheck()
{
-
+ MeasureInvalidated += (sender, args) =>
+ {
+ InvalidateMeasureCount++;
+ };
}
- internal override void InvalidateMeasureInternal(InvalidationEventArgs trigger)
+ internal override void InvalidateMeasureInternal(InvalidationTrigger trigger)
{
base.InvalidateMeasureInternal(trigger);
- InvalidateMeasureCount++;
+ PlatformInvalidateMeasureCount++;
}
}
class InvalidatePageInvalidateMeasureCheck : ContentPage
{
+ public int PlatformInvalidateMeasureCount { get; set; }
public int InvalidateMeasureCount { get; set; }
public InvalidatePageInvalidateMeasureCheck()
{
-
+ MeasureInvalidated += (sender, args) =>
+ {
+ InvalidateMeasureCount++;
+ };
}
- internal override void InvalidateMeasureInternal(InvalidationEventArgs trigger)
+ internal override void InvalidateMeasureInternal(InvalidationTrigger trigger)
{
base.InvalidateMeasureInternal(trigger);
- InvalidateMeasureCount++;
+ PlatformInvalidateMeasureCount++;
}
}
}
diff --git a/src/Controls/tests/Core.UnitTests/VisualElementTests.cs b/src/Controls/tests/Core.UnitTests/VisualElementTests.cs
index 05374344f645..8ddabfbc1d12 100644
--- a/src/Controls/tests/Core.UnitTests/VisualElementTests.cs
+++ b/src/Controls/tests/Core.UnitTests/VisualElementTests.cs
@@ -317,79 +317,5 @@ public void WidthAndHeightRequestPropagateToHandler()
Assert.Equal(2, heightMapperCalled);
Assert.Equal(2, widthMapperCalled);
}
-
- [Fact]
- public void ShouldPropagateVisibilityToChildren()
- {
- var grid = new Grid() { IsVisible = false };
- var label = new Label() { IsVisible = true };
- grid.Add(label);
-
- Assert.False(label.IsVisible);
- Assert.Equal(grid.IsVisible, label.IsVisible);
- }
-
- [Theory]
- [InlineData(false, true, true, false, false, false)]
- [InlineData(true, false, true, true, false, false)]
- public void IsVisiblePropagates(bool rootIsVisible, bool nestedIsVisible, bool childIsVisible, bool expectedRootVisibility, bool expectedNestedVisibility, bool expectedChildVisibility)
- {
- var root = new Grid() { IsVisible = rootIsVisible };
- var nested = new Grid() { IsVisible = nestedIsVisible };
- var child = new Button() { IsVisible = childIsVisible };
-
- nested.Add(child);
- root.Add(nested);
-
- Assert.Equal(root.IsVisible, expectedRootVisibility);
- Assert.Equal(nested.IsVisible, expectedNestedVisibility);
- Assert.Equal(child.IsVisible, expectedChildVisibility);
- }
-
- [Fact]
- public void IsVisibleParentCorrectlyUnsetsPropagatedChange()
- {
- var button = new Button();
- var grid = new Grid { button };
-
- grid.IsVisible = false;
- Assert.False(button.IsVisible);
-
- grid.IsVisible = true;
- Assert.True(button.IsVisible);
- }
-
- [Fact]
- public void ButtonShouldStayHiddenIfExplicitlySet()
- {
- var button = new Button { IsVisible = false };
- var grid = new Grid { button };
-
- grid.IsVisible = false;
- Assert.False(button.IsVisible);
-
- // button stays hidden if it was explicitly set
- grid.IsVisible = true;
- Assert.False(button.IsVisible);
- }
-
- [Fact]
- public void ButtonShouldBeVisibleWhenExplicitlySetWhenParentIsVisible()
- {
- var button = new Button { IsVisible = false };
- var grid = new Grid { button };
-
- // everything is hidden
- grid.IsVisible = false;
- Assert.False(button.IsVisible);
-
- // make button visible, but it should not appear
- button.IsVisible = true;
- Assert.False(button.IsVisible);
-
- // button appears when parent appears
- grid.IsVisible = true;
- Assert.True(button.IsVisible);
- }
}
}
diff --git a/src/Controls/tests/TestCases.Android.Tests/snapshots/android/AccessibilityTraitsSetCorrectlyMultiple.png b/src/Controls/tests/TestCases.Android.Tests/snapshots/android/AccessibilityTraitsSetCorrectlyMultiple.png
new file mode 100644
index 000000000000..eaa2d1c40c8d
Binary files /dev/null and b/src/Controls/tests/TestCases.Android.Tests/snapshots/android/AccessibilityTraitsSetCorrectlyMultiple.png differ
diff --git a/src/Controls/tests/TestCases.Android.Tests/snapshots/android/AccessibilityTraitsSetCorrectlyNone.png b/src/Controls/tests/TestCases.Android.Tests/snapshots/android/AccessibilityTraitsSetCorrectlyNone.png
new file mode 100644
index 000000000000..fb150b2a7eae
Binary files /dev/null and b/src/Controls/tests/TestCases.Android.Tests/snapshots/android/AccessibilityTraitsSetCorrectlyNone.png differ
diff --git a/src/Controls/tests/TestCases.Android.Tests/snapshots/android/AccessibilityTraitsSetCorrectlySingle.png b/src/Controls/tests/TestCases.Android.Tests/snapshots/android/AccessibilityTraitsSetCorrectlySingle.png
new file mode 100644
index 000000000000..8ea8c6b6cb91
Binary files /dev/null and b/src/Controls/tests/TestCases.Android.Tests/snapshots/android/AccessibilityTraitsSetCorrectlySingle.png differ
diff --git a/src/Controls/tests/TestCases.Android.Tests/snapshots/android/FooterWithEmptyCVShouldHaveCorrectSize.png b/src/Controls/tests/TestCases.Android.Tests/snapshots/android/FooterWithEmptyCVShouldHaveCorrectSize.png
new file mode 100644
index 000000000000..eea0182c7703
Binary files /dev/null and b/src/Controls/tests/TestCases.Android.Tests/snapshots/android/FooterWithEmptyCVShouldHaveCorrectSize.png differ
diff --git a/src/Controls/tests/TestCases.Android.Tests/snapshots/android/HeaderFooterGridHorizontalWorks.png b/src/Controls/tests/TestCases.Android.Tests/snapshots/android/HeaderFooterGridHorizontalWorks.png
new file mode 100644
index 000000000000..1388172e355d
Binary files /dev/null and b/src/Controls/tests/TestCases.Android.Tests/snapshots/android/HeaderFooterGridHorizontalWorks.png differ
diff --git a/src/Controls/tests/TestCases.Android.Tests/snapshots/android/HeaderFooterGridWorks.png b/src/Controls/tests/TestCases.Android.Tests/snapshots/android/HeaderFooterGridWorks.png
new file mode 100644
index 000000000000..75e34a36b56b
Binary files /dev/null and b/src/Controls/tests/TestCases.Android.Tests/snapshots/android/HeaderFooterGridWorks.png differ
diff --git a/src/Controls/tests/TestCases.Android.Tests/snapshots/android/HeaderFooterTemplateWorks.png b/src/Controls/tests/TestCases.Android.Tests/snapshots/android/HeaderFooterTemplateWorks.png
new file mode 100644
index 000000000000..cb1e3dff6dfe
Binary files /dev/null and b/src/Controls/tests/TestCases.Android.Tests/snapshots/android/HeaderFooterTemplateWorks.png differ
diff --git a/src/Controls/tests/TestCases.Android.Tests/snapshots/android/VerifyWebViewBackgroundColor.png b/src/Controls/tests/TestCases.Android.Tests/snapshots/android/VerifyWebViewBackgroundColor.png
new file mode 100644
index 000000000000..5d766ec30d27
Binary files /dev/null and b/src/Controls/tests/TestCases.Android.Tests/snapshots/android/VerifyWebViewBackgroundColor.png differ
diff --git a/src/Controls/tests/TestCases.Android.Tests/snapshots/android/VerifyWebViewDynamicBackgroundColor.png b/src/Controls/tests/TestCases.Android.Tests/snapshots/android/VerifyWebViewDynamicBackgroundColor.png
new file mode 100644
index 000000000000..c45b5c0b710f
Binary files /dev/null and b/src/Controls/tests/TestCases.Android.Tests/snapshots/android/VerifyWebViewDynamicBackgroundColor.png differ
diff --git a/src/Controls/tests/TestCases.HostApp/Elements/CollectionView/HeaderFooterGalleries/HeaderFooterGallery.cs b/src/Controls/tests/TestCases.HostApp/Elements/CollectionView/HeaderFooterGalleries/HeaderFooterGallery.cs
index 470e1470be52..bcca9a5a0aeb 100644
--- a/src/Controls/tests/TestCases.HostApp/Elements/CollectionView/HeaderFooterGalleries/HeaderFooterGallery.cs
+++ b/src/Controls/tests/TestCases.HostApp/Elements/CollectionView/HeaderFooterGalleries/HeaderFooterGallery.cs
@@ -20,6 +20,7 @@ public HeaderFooterGallery()
descriptionLabel,
TestBuilder.NavButton("Header/Footer (String)", () => new HeaderFooterString(), Navigation),
TestBuilder.NavButton("Header/Footer (Forms View)", () => new HeaderFooterView(), Navigation),
+ TestBuilder.NavButton("Header/Footer (Horizontal Forms View)", () => new HeaderFooterViewHorizontal(), Navigation),
TestBuilder.NavButton("Header/Footer (Template)", () => new HeaderFooterTemplate(), Navigation),
TestBuilder.NavButton("Header/Footer (Grid)", () => new HeaderFooterGrid(), Navigation),
TestBuilder.NavButton("Footer Only (String)", () => new FooterOnlyString(), Navigation),
diff --git a/src/Controls/tests/TestCases.HostApp/Elements/CollectionView/HeaderFooterGalleries/HeaderFooterViewHorizontal.xaml b/src/Controls/tests/TestCases.HostApp/Elements/CollectionView/HeaderFooterGalleries/HeaderFooterViewHorizontal.xaml
new file mode 100644
index 000000000000..9e960d75a10b
--- /dev/null
+++ b/src/Controls/tests/TestCases.HostApp/Elements/CollectionView/HeaderFooterGalleries/HeaderFooterViewHorizontal.xaml
@@ -0,0 +1,43 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Controls/tests/TestCases.HostApp/Elements/CollectionView/HeaderFooterGalleries/HeaderFooterViewHorizontal.xaml.cs b/src/Controls/tests/TestCases.HostApp/Elements/CollectionView/HeaderFooterGalleries/HeaderFooterViewHorizontal.xaml.cs
new file mode 100644
index 000000000000..9004b4ef6be7
--- /dev/null
+++ b/src/Controls/tests/TestCases.HostApp/Elements/CollectionView/HeaderFooterGalleries/HeaderFooterViewHorizontal.xaml.cs
@@ -0,0 +1,17 @@
+using System.Windows.Input;
+
+namespace Maui.Controls.Sample.CollectionViewGalleries.HeaderFooterGalleries
+{
+ public partial class HeaderFooterViewHorizontal : ContentPage
+ {
+ readonly HeaderFooterViewModel _viewModel = new HeaderFooterViewModel(10);
+
+ public HeaderFooterViewHorizontal()
+ {
+ InitializeComponent();
+
+ CollectionView.ItemTemplate = ExampleTemplates.PhotoTemplate();
+ BindingContext = _viewModel;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Issue10222.cs b/src/Controls/tests/TestCases.HostApp/Issues/Issue10222.cs
index 1a8f2537acc4..70c66126c137 100644
--- a/src/Controls/tests/TestCases.HostApp/Issues/Issue10222.cs
+++ b/src/Controls/tests/TestCases.HostApp/Issues/Issue10222.cs
@@ -64,9 +64,7 @@ async void InitCV()
cv.ScrollTo(items.Count - 1);
- //give the cv time to scroll
- var rand = new Random();
- await Task.Delay(rand.Next(10, 200));
+ await Task.Delay(200);
await Navigation.PopAsync(false);
diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Issue11896.xaml b/src/Controls/tests/TestCases.HostApp/Issues/Issue11896.xaml
index 684cdcbbf3a2..6d322c10b576 100644
--- a/src/Controls/tests/TestCases.HostApp/Issues/Issue11896.xaml
+++ b/src/Controls/tests/TestCases.HostApp/Issues/Issue11896.xaml
@@ -17,9 +17,9 @@
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
\ No newline at end of file
diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Issue25362.xaml.cs b/src/Controls/tests/TestCases.HostApp/Issues/Issue25362.xaml.cs
index f72fa2831aee..e2ad956bb3ee 100644
--- a/src/Controls/tests/TestCases.HostApp/Issues/Issue25362.xaml.cs
+++ b/src/Controls/tests/TestCases.HostApp/Issues/Issue25362.xaml.cs
@@ -17,7 +17,7 @@ public partial class Issue25362 : ContentPage
public Issue25362()
{
InitializeComponent();
- ItemList = new() { "Item1", "Item2", "Itme3" };
+ ItemList = new() { "Item1", "Item2", "Item3" };
ItemListHeader = new() { "HeaderItem1" };
BindingContext = this;
}
diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Issue28580.xaml b/src/Controls/tests/TestCases.HostApp/Issues/Issue28580.xaml
new file mode 100644
index 000000000000..031e45f8384e
--- /dev/null
+++ b/src/Controls/tests/TestCases.HostApp/Issues/Issue28580.xaml
@@ -0,0 +1,58 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Issue28580.xaml.cs b/src/Controls/tests/TestCases.HostApp/Issues/Issue28580.xaml.cs
new file mode 100644
index 000000000000..6906ed6f8733
--- /dev/null
+++ b/src/Controls/tests/TestCases.HostApp/Issues/Issue28580.xaml.cs
@@ -0,0 +1,10 @@
+namespace Maui.Controls.Sample.Issues;
+
+[Issue(IssueTracker.Github, 28580, "CollectionView footer sizing when source is empty")]
+public partial class Issue28580 : ContentPage
+{
+ public Issue28580()
+ {
+ InitializeComponent();
+ }
+}
\ No newline at end of file
diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Issue28657.cs b/src/Controls/tests/TestCases.HostApp/Issues/Issue28657.cs
new file mode 100644
index 000000000000..39a9a97afdb7
--- /dev/null
+++ b/src/Controls/tests/TestCases.HostApp/Issues/Issue28657.cs
@@ -0,0 +1,38 @@
+namespace Controls.TestCases.HostApp.Issues;
+
+[Issue(IssueTracker.Github, 28657, "iOS - Rotating the simulator would cause clipping on the description text", PlatformAffected.iOS)]
+class Issue28657 : ContentPage
+{
+ public Issue28657()
+ {
+ var cv = new CollectionView();
+ cv.ItemTemplate = new DataTemplate(() =>
+ {
+ var label = new Label();
+ label.BackgroundColor = Colors.DeepSkyBlue;
+ label.LineBreakMode = LineBreakMode.CharacterWrap;
+ label.SetBinding(Label.TextProperty, ".");
+ var vsl = new VerticalStackLayout { Padding = 8 };
+ vsl.Add(label);
+ vsl.BackgroundColor = Colors.SlateBlue;
+ return vsl;
+ });
+ cv.ItemsSource = Enumerable.Range(0, 30)
+ .Select(x => x + ": Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec a diam lectus. Sed sit amet ipsum mauris. Maecenas congue ligula ac quam viverra nec consectetur ante hendrerit.")
+ .ToList();
+ var label = new Label
+ {
+ AutomationId = "StubLabel",
+ Text = "Rotate the device until you get back to portrait mode. The text should wrap normally on each row.",
+ };
+ var grid = new Grid
+ {
+ RowDefinitions = new RowDefinitionCollection(
+ new RowDefinition(GridLength.Auto),
+ new RowDefinition(GridLength.Star))
+ };
+ grid.Add(label);
+ grid.Add(cv, 0, 1);
+ Content = grid;
+ }
+}
diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Issue28714.cs b/src/Controls/tests/TestCases.HostApp/Issues/Issue28714.cs
new file mode 100644
index 000000000000..cfed66268745
--- /dev/null
+++ b/src/Controls/tests/TestCases.HostApp/Issues/Issue28714.cs
@@ -0,0 +1,48 @@
+namespace Maui.Controls.Sample.Issues;
+
+[Issue(IssueTracker.Github, 28714, "[iOS] WebView BackgroundColor is not setting correctly", PlatformAffected.iOS)]
+public partial class Issue28714 : ContentPage
+{
+ public Issue28714()
+ {
+ BackgroundColor = Colors.YellowGreen;
+ var verticalStackLayout = new VerticalStackLayout();
+ verticalStackLayout.Spacing = 20;
+
+ var webView = new WebView()
+ {
+ HeightRequest = 300,
+ WidthRequest = 400,
+ BackgroundColor = Colors.Transparent,
+ Source = new HtmlWebViewSource
+ {
+ Html = @"
+
+
+
+ Welcome to WebView
+
+
+ "
+ }
+
+ };
+
+ var button = new Button
+ {
+ Text = "Change WebView BackgroundColor",
+ AutomationId = "button"
+ };
+ button.Clicked += (s, e) =>
+ {
+ webView.BackgroundColor = Colors.Red;
+ };
+
+ verticalStackLayout.Add(button);
+ verticalStackLayout.Add(webView);
+
+
+
+ Content = verticalStackLayout;
+ }
+}
\ No newline at end of file
diff --git a/src/Controls/tests/TestCases.Mac.Tests/snapshots/mac/AccessibilityTraitsSetCorrectlyMultiple.png b/src/Controls/tests/TestCases.Mac.Tests/snapshots/mac/AccessibilityTraitsSetCorrectlyMultiple.png
index a6e7d67d564e..136f60e5e893 100644
Binary files a/src/Controls/tests/TestCases.Mac.Tests/snapshots/mac/AccessibilityTraitsSetCorrectlyMultiple.png and b/src/Controls/tests/TestCases.Mac.Tests/snapshots/mac/AccessibilityTraitsSetCorrectlyMultiple.png differ
diff --git a/src/Controls/tests/TestCases.Mac.Tests/snapshots/mac/AccessibilityTraitsSetCorrectlyNone.png b/src/Controls/tests/TestCases.Mac.Tests/snapshots/mac/AccessibilityTraitsSetCorrectlyNone.png
index f7a3dd951dea..acf0ebb23073 100644
Binary files a/src/Controls/tests/TestCases.Mac.Tests/snapshots/mac/AccessibilityTraitsSetCorrectlyNone.png and b/src/Controls/tests/TestCases.Mac.Tests/snapshots/mac/AccessibilityTraitsSetCorrectlyNone.png differ
diff --git a/src/Controls/tests/TestCases.Mac.Tests/snapshots/mac/AccessibilityTraitsSetCorrectlySingle.png b/src/Controls/tests/TestCases.Mac.Tests/snapshots/mac/AccessibilityTraitsSetCorrectlySingle.png
index a789921dd3ce..6147d41b67b5 100644
Binary files a/src/Controls/tests/TestCases.Mac.Tests/snapshots/mac/AccessibilityTraitsSetCorrectlySingle.png and b/src/Controls/tests/TestCases.Mac.Tests/snapshots/mac/AccessibilityTraitsSetCorrectlySingle.png differ
diff --git a/src/Controls/tests/TestCases.Mac.Tests/snapshots/mac/CollectionViewMeasureFirstItem.png b/src/Controls/tests/TestCases.Mac.Tests/snapshots/mac/CollectionViewMeasureFirstItem.png
index ae05a6e024c9..743a7f704247 100644
Binary files a/src/Controls/tests/TestCases.Mac.Tests/snapshots/mac/CollectionViewMeasureFirstItem.png and b/src/Controls/tests/TestCases.Mac.Tests/snapshots/mac/CollectionViewMeasureFirstItem.png differ
diff --git a/src/Controls/tests/TestCases.Mac.Tests/snapshots/mac/DynamicFontImageSourceColorShouldApplyOnTabIcon.png b/src/Controls/tests/TestCases.Mac.Tests/snapshots/mac/DynamicFontImageSourceColorShouldApplyOnTabIcon.png
index fb4ce79b2e8b..636ced77f537 100644
Binary files a/src/Controls/tests/TestCases.Mac.Tests/snapshots/mac/DynamicFontImageSourceColorShouldApplyOnTabIcon.png and b/src/Controls/tests/TestCases.Mac.Tests/snapshots/mac/DynamicFontImageSourceColorShouldApplyOnTabIcon.png differ
diff --git a/src/Controls/tests/TestCases.Mac.Tests/snapshots/mac/EntryClearButtonColorShouldMatchTextColor.png b/src/Controls/tests/TestCases.Mac.Tests/snapshots/mac/EntryClearButtonColorShouldMatchTextColor.png
index 19b35e24cce2..213bb341426d 100644
Binary files a/src/Controls/tests/TestCases.Mac.Tests/snapshots/mac/EntryClearButtonColorShouldMatchTextColor.png and b/src/Controls/tests/TestCases.Mac.Tests/snapshots/mac/EntryClearButtonColorShouldMatchTextColor.png differ
diff --git a/src/Controls/tests/TestCases.Mac.Tests/snapshots/mac/FontImageSourceColorShouldApplyOnTabIcon.png b/src/Controls/tests/TestCases.Mac.Tests/snapshots/mac/FontImageSourceColorShouldApplyOnTabIcon.png
index 3e44b85513a7..fba52950c6cb 100644
Binary files a/src/Controls/tests/TestCases.Mac.Tests/snapshots/mac/FontImageSourceColorShouldApplyOnTabIcon.png and b/src/Controls/tests/TestCases.Mac.Tests/snapshots/mac/FontImageSourceColorShouldApplyOnTabIcon.png differ
diff --git a/src/Controls/tests/TestCases.Mac.Tests/snapshots/mac/FooterWithEmptyCVShouldHaveCorrectSize.png b/src/Controls/tests/TestCases.Mac.Tests/snapshots/mac/FooterWithEmptyCVShouldHaveCorrectSize.png
new file mode 100644
index 000000000000..5caf8805e298
Binary files /dev/null and b/src/Controls/tests/TestCases.Mac.Tests/snapshots/mac/FooterWithEmptyCVShouldHaveCorrectSize.png differ
diff --git a/src/Controls/tests/TestCases.Mac.Tests/snapshots/mac/Issue22899Test.png b/src/Controls/tests/TestCases.Mac.Tests/snapshots/mac/Issue22899Test.png
index 9671163a57c5..10fcf9fa4152 100644
Binary files a/src/Controls/tests/TestCases.Mac.Tests/snapshots/mac/Issue22899Test.png and b/src/Controls/tests/TestCases.Mac.Tests/snapshots/mac/Issue22899Test.png differ
diff --git a/src/Controls/tests/TestCases.Mac.Tests/snapshots/mac/SelectedTabIconShouldChangeColor.png b/src/Controls/tests/TestCases.Mac.Tests/snapshots/mac/SelectedTabIconShouldChangeColor.png
index 266e554627fb..c367c8d5bf4b 100644
Binary files a/src/Controls/tests/TestCases.Mac.Tests/snapshots/mac/SelectedTabIconShouldChangeColor.png and b/src/Controls/tests/TestCases.Mac.Tests/snapshots/mac/SelectedTabIconShouldChangeColor.png differ
diff --git a/src/Controls/tests/TestCases.Mac.Tests/snapshots/mac/TabbedPageBackButtonUpdated.png b/src/Controls/tests/TestCases.Mac.Tests/snapshots/mac/TabbedPageBackButtonUpdated.png
index b016e16163ce..a63ebbead090 100644
Binary files a/src/Controls/tests/TestCases.Mac.Tests/snapshots/mac/TabbedPageBackButtonUpdated.png and b/src/Controls/tests/TestCases.Mac.Tests/snapshots/mac/TabbedPageBackButtonUpdated.png differ
diff --git a/src/Controls/tests/TestCases.Mac.Tests/snapshots/mac/TextInEditorShouldScroll.png b/src/Controls/tests/TestCases.Mac.Tests/snapshots/mac/TextInEditorShouldScroll.png
index 160d4dba5acc..62f0cc6010fd 100644
Binary files a/src/Controls/tests/TestCases.Mac.Tests/snapshots/mac/TextInEditorShouldScroll.png and b/src/Controls/tests/TestCases.Mac.Tests/snapshots/mac/TextInEditorShouldScroll.png differ
diff --git a/src/Controls/tests/TestCases.Mac.Tests/snapshots/mac/UpdatedSelectionIndicatorProperly.png b/src/Controls/tests/TestCases.Mac.Tests/snapshots/mac/UpdatedSelectionIndicatorProperly.png
index fb8d9e169e09..0705092c4453 100644
Binary files a/src/Controls/tests/TestCases.Mac.Tests/snapshots/mac/UpdatedSelectionIndicatorProperly.png and b/src/Controls/tests/TestCases.Mac.Tests/snapshots/mac/UpdatedSelectionIndicatorProperly.png differ
diff --git a/src/Controls/tests/TestCases.Mac.Tests/snapshots/mac/VerifyWebViewBackgroundColor.png b/src/Controls/tests/TestCases.Mac.Tests/snapshots/mac/VerifyWebViewBackgroundColor.png
new file mode 100644
index 000000000000..e5c105c16b80
Binary files /dev/null and b/src/Controls/tests/TestCases.Mac.Tests/snapshots/mac/VerifyWebViewBackgroundColor.png differ
diff --git a/src/Controls/tests/TestCases.Mac.Tests/snapshots/mac/VerifyWebViewDynamicBackgroundColor.png b/src/Controls/tests/TestCases.Mac.Tests/snapshots/mac/VerifyWebViewDynamicBackgroundColor.png
new file mode 100644
index 000000000000..fe1457ef8baf
Binary files /dev/null and b/src/Controls/tests/TestCases.Mac.Tests/snapshots/mac/VerifyWebViewDynamicBackgroundColor.png differ
diff --git a/src/Controls/tests/TestCases.Shared.Tests/Tests/CollectionView/CollectionViewUITests.HeaderAndFooter.cs b/src/Controls/tests/TestCases.Shared.Tests/Tests/CollectionView/CollectionViewUITests.HeaderAndFooter.cs
index 0192359dff2b..08eaa7f562b8 100644
--- a/src/Controls/tests/TestCases.Shared.Tests/Tests/CollectionView/CollectionViewUITests.HeaderAndFooter.cs
+++ b/src/Controls/tests/TestCases.Shared.Tests/Tests/CollectionView/CollectionViewUITests.HeaderAndFooter.cs
@@ -28,7 +28,7 @@ public void HeaderFooterStringWorks()
App.WaitForElement("Just a string as a header");
App.WaitForElement("This footer is also a string");
}
-#if IOS
+#if IOS || ANDROID
[Test]
[Category(UITestCategories.CollectionView)]
public void HeaderFooterViewWorks()
@@ -43,6 +43,29 @@ public void HeaderFooterViewWorks()
App.WaitForElement("This Is A Footer");
}
+ [Test]
+ [Category(UITestCategories.CollectionView)]
+ public void HeaderFooterHorizontalViewWorks()
+ {
+ // Navigate to the selection galleries
+ VisitInitialGallery("Header Footer");
+
+ // Navigate to the specific sample inside selection galleries
+ VisitSubGallery("Header/Footer (Horizontal Forms View)");
+
+ // Verify the header is visible
+ App.WaitForElement("This Is A Header");
+
+ // Scroll right to ensure the footer is visible and positioned at the end
+ for (int i = 0; i < 5; i++)
+ {
+ App.ScrollRight("CV", ScrollStrategy.Auto, 0.9, 250);
+ }
+
+ // Verify the footer is visible
+ App.WaitForElement("This Is A Footer");
+ }
+
[Test]
[Category(UITestCategories.CollectionView)]
public void HeaderFooterTemplateWorks()
@@ -67,7 +90,11 @@ public void HeaderFooterGridWorks()
VisitSubGallery("Header/Footer (Grid)");
App.WaitForElement("This Is A Header");
+#if !ANDROID
+ // Android screen is too small to show this label
+ // but we can check for the footer via screenshot
App.WaitForElement("This Is A Footer");
+#endif
VerifyScreenshot();
}
diff --git a/src/Controls/tests/TestCases.Shared.Tests/Tests/DragAndDropUITests.cs b/src/Controls/tests/TestCases.Shared.Tests/Tests/DragAndDropUITests.cs
index 10892df95305..52e0a552fa10 100644
--- a/src/Controls/tests/TestCases.Shared.Tests/Tests/DragAndDropUITests.cs
+++ b/src/Controls/tests/TestCases.Shared.Tests/Tests/DragAndDropUITests.cs
@@ -360,6 +360,12 @@ public void DropEventCoordinates()
App.WaitForElement("Green");
App.DragAndDrop("Blue", "Green");
+ // Wait for all UI elements to confirm drag and drop operation completion
+ App.WaitForElement("DropRelativeLayout");
+ App.WaitForElement("DropRelativeScreen");
+ App.WaitForElement("DropRelativeLabel");
+ App.WaitForElement("DragStartRelativeScreen");
+
var dropRelativeToLayout = GetCoordinatesFromLabel(App.FindElement("DropRelativeLayout").GetText());
var dropRelativeToScreen = GetCoordinatesFromLabel(App.FindElement("DropRelativeScreen").GetText());
var dropRelativeToLabel = GetCoordinatesFromLabel(App.FindElement("DropRelativeLabel").GetText());
diff --git a/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Bugzilla/Bugzilla34912.cs b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Bugzilla/Bugzilla34912.cs
index c9fb7e733f0a..f8b5066fc2cf 100644
--- a/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Bugzilla/Bugzilla34912.cs
+++ b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Bugzilla/Bugzilla34912.cs
@@ -17,10 +17,14 @@ public Bugzilla34912(TestDevice testDevice) : base(testDevice)
[Category(UITestCategories.ListView)]
public void Bugzilla34912Test()
{
+ App.WaitForElement("Allen");
App.Tap("Allen");
App.WaitForElement("You tapped Allen");
+ App.WaitForElement("OK");
App.Tap("OK");
+ App.WaitForElement("Disable ListView");
App.Tap("Disable ListView");
+ App.WaitForElement("Allen");
App.Tap("Allen");
App.WaitForNoElement("You tapped Allen");
}
diff --git a/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/CarouselViewUITests.LoopNoFreeze.cs b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/CarouselViewUITests.LoopNoFreeze.cs
index dbc3f7483c77..736fc3617118 100644
--- a/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/CarouselViewUITests.LoopNoFreeze.cs
+++ b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/CarouselViewUITests.LoopNoFreeze.cs
@@ -1,4 +1,4 @@
-#if TEST_FAILS_ON_WINDOWS // related issue: https://github.com/dotnet/maui/issues/24482
+#if TEST_FAILS_ON_WINDOWS && TEST_FAILS_ON_ANDROID // Related issue for windows: https://github.com/dotnet/maui/issues/24482 and For Android, see : https://github.com/dotnet/maui/issues/28760
using NUnit.Framework;
using UITest.Appium;
using UITest.Core;
diff --git a/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue10222.cs b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue10222.cs
index 5d241620b172..34b94d7f2f14 100644
--- a/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue10222.cs
+++ b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue10222.cs
@@ -18,8 +18,8 @@ public void Issue10222Test()
{
App.WaitForElement("goTo");
App.Tap("goTo");
- App.WaitForElement("items1");
- App.WaitForElement("goTo");
+ App.WaitForElement("items1", timeout: TimeSpan.FromSeconds(1));
+ App.WaitForElement("goTo", timeout: TimeSpan.FromSeconds(2));
}
}
#endif
\ No newline at end of file
diff --git a/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue19214.cs b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue19214.cs
index c7c4964ab342..a0eb66546d9d 100644
--- a/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue19214.cs
+++ b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue19214.cs
@@ -1,4 +1,4 @@
-#if IOS || (ANDROID && TEST_FAILS_ON_ANDROID)//android related issue: https://github.com/dotnet/maui/issues/27951
+#if (IOS && TEST_FAILS_ON_IOS) || (ANDROID && TEST_FAILS_ON_ANDROID) // Android related issue: https://github.com/dotnet/maui/issues/27951, iOS related issue: https://github.com/dotnet/maui/issues/28760
//The test is applicable only to mobile platforms like iOS and Android.
using System.Drawing;
using NUnit.Framework;
diff --git a/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue19500.cs b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue19500.cs
index d3adf44e6fc0..6dbda190aa60 100644
--- a/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue19500.cs
+++ b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue19500.cs
@@ -1,4 +1,4 @@
-using NUnit.Framework;
+using NUnit.Framework;
using UITest.Appium;
using UITest.Core;
@@ -19,6 +19,11 @@ public void TextInEditorShouldScroll()
_ = App.WaitForElement("editor");
App.ScrollDown("editor");
+#if MACCATALYST // In Catalyst scroll down is not effective so here we retry one more time to address the flakyness.
+ Thread.Sleep(500);
+ App.ScrollDown("editor");
+#endif
+
// The test passes if the text inside the editor scrolls down
VerifyScreenshot();
}
diff --git a/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue19509.cs b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue19509.cs
index 604accabda78..4935ea71c9cf 100644
--- a/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue19509.cs
+++ b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue19509.cs
@@ -1,3 +1,4 @@
+#if TEST_FAILS_ON_IOS //For more info see: https://github.com/dotnet/maui/issues/28806
using NUnit.Framework;
using UITest.Appium;
using UITest.Core;
@@ -28,3 +29,4 @@ public async Task EntryTextColorStopsWorkingAfterPropertyIsUpdatedFromBinding()
}
}
}
+#endif
\ No newline at end of file
diff --git a/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue25473.cs b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue25473.cs
index aa5c25fd9de9..cafd3d06f605 100644
--- a/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue25473.cs
+++ b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue25473.cs
@@ -27,7 +27,12 @@ public void VerifyEntryClearButtonVisibilitySetToWhileEditing()
App.DismissKeyboard();
}
#endif
+
+#if IOS //Inconsistent keyboard visibility issue in iOS CI environments can cause test flakiness. As this test validate the clear button visibility only, so the keyboard is not mandatory.
+ VerifyScreenshot(cropBottom: 1200);
+#else
VerifyScreenshot();
+#endif
}
[Test]
@@ -45,7 +50,12 @@ public void VerifyEntryClearButtonVisibilitySetToNever()
App.DismissKeyboard();
}
#endif
+
+#if IOS //Inconsistent keyboard visibility issue in iOS CI environments can cause test flakiness. As this test validate the clear button visibility only, so the keyboard is not mandatory.
+ VerifyScreenshot(cropBottom: 1200);
+#else
VerifyScreenshot();
+#endif
}
}
}
\ No newline at end of file
diff --git a/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue25671.cs b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue25671.cs
index baa8499ee319..07201f1d01bc 100644
--- a/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue25671.cs
+++ b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue25671.cs
@@ -42,13 +42,13 @@ public async Task LayoutPassesShouldNotIncrease()
var arrangePasses = int.Parse(match.Groups[2].Value);
#if IOS
- var maxMeasurePasses = 221;
- var maxArrangePasses = 237;
+ var maxMeasurePasses = 225;
+ var maxArrangePasses = 247;
if (App.FindElement("HeadingLabel").GetText() == "CollectionViewHandler2")
{
- maxMeasurePasses = 362;
- maxArrangePasses = 398;
+ maxMeasurePasses = 380;
+ maxArrangePasses = 295;
}
#elif ANDROID
const int maxMeasurePasses = 353;
diff --git a/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue26817.cs b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue26817.cs
index 4a139e82a58e..6d57483969b5 100644
--- a/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue26817.cs
+++ b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue26817.cs
@@ -1,4 +1,4 @@
-#if MACCATALYST || IOS
+#if MACCATALYST || IOS || ANDROID
using NUnit.Framework;
using UITest.Appium;
using UITest.Core;
diff --git a/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue28580.cs b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue28580.cs
new file mode 100644
index 000000000000..0c6e4877ae1c
--- /dev/null
+++ b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue28580.cs
@@ -0,0 +1,21 @@
+using NUnit.Framework;
+using UITest.Appium;
+using UITest.Core;
+
+namespace Microsoft.Maui.TestCases.Tests.Issues;
+public class Issue28580 : _IssuesUITest
+{
+ public Issue28580(TestDevice testDevice) : base(testDevice)
+ {
+ }
+
+ public override string Issue => "CollectionView footer sizing when source is empty";
+
+ [Test]
+ [Category(UITestCategories.CollectionView)]
+ public void FooterWithEmptyCVShouldHaveCorrectSize()
+ {
+ App.WaitForElement("labelInFooter");
+ VerifyScreenshot();
+ }
+}
\ No newline at end of file
diff --git a/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue28657.cs b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue28657.cs
new file mode 100644
index 000000000000..96d1b3fee2cd
--- /dev/null
+++ b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue28657.cs
@@ -0,0 +1,28 @@
+#if IOS
+using NUnit.Framework;
+using UITest.Appium;
+using UITest.Core;
+
+namespace Microsoft.Maui.TestCases.Tests.Issues;
+
+public class Issue28657 : _IssuesUITest
+{
+ public override string Issue => "iOS - Rotating the simulator would cause clipping on the description text";
+ public Issue28657(TestDevice device) : base(device)
+ {
+ }
+
+ [Test]
+ [Category(UITestCategories.CollectionView)]
+ public void CellLayoutUpdatesCorrectlyAfterDeviceOrientationChanges()
+ {
+ App.WaitForElement("StubLabel");
+ App.SetOrientationLandscape();
+ Thread.Sleep(400);
+ VerifyScreenshot("Issue28657_Landscape");
+ App.SetOrientationPortrait();
+ Thread.Sleep(400);
+ VerifyScreenshot("Issue28657_Portrait");
+ }
+}
+#endif
\ No newline at end of file
diff --git a/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue28714.cs b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue28714.cs
new file mode 100644
index 000000000000..7534ff1701b5
--- /dev/null
+++ b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue28714.cs
@@ -0,0 +1,32 @@
+#if TEST_FAILS_ON_WINDOWS // The transparent background color is not working on Windows, refer to https://github.com/microsoft/microsoft-ui-xaml/issues/6527
+using NUnit.Framework;
+using UITest.Appium;
+using UITest.Core;
+
+namespace Microsoft.Maui.TestCases.Tests.Issues;
+public class Issue28714 : _IssuesUITest
+{
+ public override string Issue => "[iOS] WebView BackgroundColor is not setting correctly";
+
+ public Issue28714(TestDevice device)
+ : base(device)
+ { }
+
+ [Test, Order(1)]
+ [Category(UITestCategories.WebView)]
+ public void VerifyWebViewBackgroundColor()
+ {
+ App.WaitForElement("button");
+ VerifyScreenshot();
+ }
+
+ [Test, Order(2)]
+ [Category(UITestCategories.WebView)]
+ public void VerifyWebViewDynamicBackgroundColor()
+ {
+ App.WaitForElement("button");
+ App.Tap("button");
+ VerifyScreenshot();
+ }
+}
+#endif
\ No newline at end of file
diff --git a/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue3049.cs b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue3049.cs
index 51f76991fcc4..96335164464a 100644
--- a/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue3049.cs
+++ b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue3049.cs
@@ -11,6 +11,7 @@ public class Issue3049 : _IssuesUITest
const string Button1Id = "button1";
const string Button2Id = "button2";
const string Success = "Success";
+ const string Skip = "skip";
public Issue3049(TestDevice testDevice) : base(testDevice)
{
@@ -22,16 +23,18 @@ public Issue3049(TestDevice testDevice) : base(testDevice)
[Category(UITestCategories.DisplayAlert)]
[Category(UITestCategories.Compatibility)]
[FailsOnIOSWhenRunningOnXamarinUITest("Skip this test -- as it is not applicable since the host app is not run on iPad in CI")]
- public async Task Issue3049Test()
+ public void Issue3049Test()
{
App.WaitForElement(Button1Id);
+ var skipLabelRect = App.WaitForElement(Skip).GetRect();
+
App.Tap(Button1Id);
- await Task.Delay(500);
+ App.WaitForElement("Click outside ActionSheet instead");
// Tap outside ActionSheet to dismiss it
- App.TapCoordinates(50, 100);
+ App.TapCoordinates(skipLabelRect.CenterX(), skipLabelRect.CenterY());
App.WaitForElement(Button2Id);
App.Tap(Button2Id);
diff --git a/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/XFIssue/Issue12652.cs b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/XFIssue/Issue12652.cs
index 84ad75953044..2d0ccdcfade7 100644
--- a/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/XFIssue/Issue12652.cs
+++ b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/XFIssue/Issue12652.cs
@@ -26,6 +26,7 @@ public void NavigatingBackToAlreadySelectedTopTabDoesntCrash()
#if WINDOWS
App.Tap("navViewItem");
#endif
+ App.WaitForElement(Top3);
App.Tap(Top3);
App.WaitForElement("TopTabPage3");
App.Tap("Main 2");
@@ -38,6 +39,7 @@ public void NavigatingBackToAlreadySelectedTopTabDoesntCrash()
#if WINDOWS
App.TapCoordinates(50, 50);
#endif
+ App.WaitForElement("Main 2");
App.Tap("Main 2");
App.WaitForElement("TopTabPage2");
App.Tap("Main 1");
diff --git a/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/XFIssue/Issue7678.cs b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/XFIssue/Issue7678.cs
index 05f2b86870da..e6e0df2d48da 100644
--- a/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/XFIssue/Issue7678.cs
+++ b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/XFIssue/Issue7678.cs
@@ -15,7 +15,7 @@ public Issue7678(TestDevice device) : base(device)
[Category(UITestCategories.CarouselView)]
public void VerifyCarouselViewItemsRenderAfterBinding()
{
- App.WaitForElement("carouselView", timeout: TimeSpan.FromSeconds(2));
+ App.WaitForElement("carouselView", timeout: TimeSpan.FromSeconds(4));
App.WaitForElementTillPageNavigationSettled("1");
}
}
diff --git a/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/XFIssue/Issue892.cs b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/XFIssue/Issue892.cs
index 0fbcd77cca8c..e01e971fa2cb 100644
--- a/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/XFIssue/Issue892.cs
+++ b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/XFIssue/Issue892.cs
@@ -55,6 +55,7 @@ void NavigateToEndAndBack(string BackButtonId)
App.WaitForElement("Pop two");
App.WaitForElementTillPageNavigationSettled("Check back two");
App.TapBackArrow(BackButtonId);
+ App.WaitForElementTillPageNavigationSettled("Check back three");
App.Tap("Check back three");
App.WaitForElement("At root");
}
diff --git a/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/XFIssue/ShellInsets.cs b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/XFIssue/ShellInsets.cs
index 6b73d8fed03c..46bc62808af5 100644
--- a/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/XFIssue/ShellInsets.cs
+++ b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/XFIssue/ShellInsets.cs
@@ -129,6 +129,7 @@ public void PaddingWithoutSafeArea()
Assert.That(zeroPadding, Is.EqualTo(1));
App.WaitForElement(ResetButton);
App.Tap(ResetButton);
+ App.WaitForElement(PaddingEntry);
App.EnterText(PaddingEntry, "100");
App.WaitForElement(PaddingTest);
App.Tap(PaddingTest);
diff --git a/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/FooterWithEmptyCVShouldHaveCorrectSize.png b/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/FooterWithEmptyCVShouldHaveCorrectSize.png
new file mode 100644
index 000000000000..196b931050bc
Binary files /dev/null and b/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/FooterWithEmptyCVShouldHaveCorrectSize.png differ
diff --git a/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/AccessibilityTraitsSetCorrectlyMultiple.png b/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/AccessibilityTraitsSetCorrectlyMultiple.png
index a4f730227b58..b3c4afeee975 100644
Binary files a/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/AccessibilityTraitsSetCorrectlyMultiple.png and b/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/AccessibilityTraitsSetCorrectlyMultiple.png differ
diff --git a/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/AccessibilityTraitsSetCorrectlyNone.png b/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/AccessibilityTraitsSetCorrectlyNone.png
index 9940cffcb1b6..8fe5ba1d9497 100644
Binary files a/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/AccessibilityTraitsSetCorrectlyNone.png and b/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/AccessibilityTraitsSetCorrectlyNone.png differ
diff --git a/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/AccessibilityTraitsSetCorrectlySingle.png b/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/AccessibilityTraitsSetCorrectlySingle.png
index 8452f168f34a..fb7328937ff8 100644
Binary files a/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/AccessibilityTraitsSetCorrectlySingle.png and b/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/AccessibilityTraitsSetCorrectlySingle.png differ
diff --git a/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/CarouselViewItemsShouldRenderVertically.png b/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/CarouselViewItemsShouldRenderVertically.png
index 9861e6f7f63f..a65a2c0714b9 100644
Binary files a/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/CarouselViewItemsShouldRenderVertically.png and b/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/CarouselViewItemsShouldRenderVertically.png differ
diff --git a/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/CollectionViewHeaderBlankWhenLastItemRemoved.png b/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/CollectionViewHeaderBlankWhenLastItemRemoved.png
index 48a4019aae67..a08408f06c0c 100644
Binary files a/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/CollectionViewHeaderBlankWhenLastItemRemoved.png and b/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/CollectionViewHeaderBlankWhenLastItemRemoved.png differ
diff --git a/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/CollectionViewMeasureFirstItem.png b/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/CollectionViewMeasureFirstItem.png
index 3ea3ac23e25a..3a2d085b905c 100644
Binary files a/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/CollectionViewMeasureFirstItem.png and b/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/CollectionViewMeasureFirstItem.png differ
diff --git a/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/CollectionviewFooterHideswhenDynamicallyAddorRemoveItems.png b/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/CollectionviewFooterHideswhenDynamicallyAddorRemoveItems.png
index 84424972a682..160d7e95ef3d 100644
Binary files a/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/CollectionviewFooterHideswhenDynamicallyAddorRemoveItems.png and b/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/CollectionviewFooterHideswhenDynamicallyAddorRemoveItems.png differ
diff --git a/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/FooterWithEmptyCVShouldHaveCorrectSize.png b/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/FooterWithEmptyCVShouldHaveCorrectSize.png
new file mode 100644
index 000000000000..e6983f6dfed0
Binary files /dev/null and b/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/FooterWithEmptyCVShouldHaveCorrectSize.png differ
diff --git a/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/HeaderFooterGridWorks.png b/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/HeaderFooterGridWorks.png
index 6c7e3ad1cc03..9ee8d4f874af 100644
Binary files a/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/HeaderFooterGridWorks.png and b/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/HeaderFooterGridWorks.png differ
diff --git a/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/HeaderFooterTemplateWorks.png b/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/HeaderFooterTemplateWorks.png
index f120cd33b90b..4b1df5e2d27e 100644
Binary files a/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/HeaderFooterTemplateWorks.png and b/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/HeaderFooterTemplateWorks.png differ
diff --git a/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/HeaderShouldNotCollapseWithItems.png b/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/HeaderShouldNotCollapseWithItems.png
index 1b92f71ad666..f2038d77ebd7 100644
Binary files a/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/HeaderShouldNotCollapseWithItems.png and b/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/HeaderShouldNotCollapseWithItems.png differ
diff --git a/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/Issue28657_Landscape.png b/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/Issue28657_Landscape.png
new file mode 100644
index 000000000000..7c0fbf1389d5
Binary files /dev/null and b/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/Issue28657_Landscape.png differ
diff --git a/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/Issue28657_Portrait.png b/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/Issue28657_Portrait.png
new file mode 100644
index 000000000000..b1314d08b264
Binary files /dev/null and b/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/Issue28657_Portrait.png differ
diff --git a/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/RefreshShouldNotChangeSize.png b/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/RefreshShouldNotChangeSize.png
index bf0c3e884f9a..a8edcc604bab 100644
Binary files a/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/RefreshShouldNotChangeSize.png and b/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/RefreshShouldNotChangeSize.png differ
diff --git a/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/VerifyEntryClearButtonVisibilitySetToNever.png b/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/VerifyEntryClearButtonVisibilitySetToNever.png
index 71c772708a31..a1d620753039 100644
Binary files a/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/VerifyEntryClearButtonVisibilitySetToNever.png and b/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/VerifyEntryClearButtonVisibilitySetToNever.png differ
diff --git a/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/VerifyEntryClearButtonVisibilitySetToWhileEditing.png b/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/VerifyEntryClearButtonVisibilitySetToWhileEditing.png
index 9e8b8c4c6bbe..7406b8ebd440 100644
Binary files a/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/VerifyEntryClearButtonVisibilitySetToWhileEditing.png and b/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/VerifyEntryClearButtonVisibilitySetToWhileEditing.png differ
diff --git a/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/VerifyWebViewBackgroundColor.png b/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/VerifyWebViewBackgroundColor.png
new file mode 100644
index 000000000000..ac9ffc851094
Binary files /dev/null and b/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/VerifyWebViewBackgroundColor.png differ
diff --git a/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/VerifyWebViewDynamicBackgroundColor.png b/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/VerifyWebViewDynamicBackgroundColor.png
new file mode 100644
index 000000000000..31f60ca92976
Binary files /dev/null and b/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/VerifyWebViewDynamicBackgroundColor.png differ
diff --git a/src/Controls/tests/Xaml.UnitTests/Issues/Issue1549.cs b/src/Controls/tests/Xaml.UnitTests/Issues/Issue1549.cs
index d07a48df3079..be3b5c618a4b 100644
--- a/src/Controls/tests/Xaml.UnitTests/Issues/Issue1549.cs
+++ b/src/Controls/tests/Xaml.UnitTests/Issues/Issue1549.cs
@@ -188,6 +188,9 @@ public void ResourcesInNonXFBaseClassesAreFound()
Assert.AreEqual(true, label00.IsVisible);
Assert.AreEqual(false, label01.IsVisible);
+
+ Assert.AreEqual(4, InvertBoolenConverter.count);
+
}
}
diff --git a/src/Core/src/Handlers/WebView/WebViewHandler.cs b/src/Core/src/Handlers/WebView/WebViewHandler.cs
index 25551172681b..acd2be502103 100644
--- a/src/Core/src/Handlers/WebView/WebViewHandler.cs
+++ b/src/Core/src/Handlers/WebView/WebViewHandler.cs
@@ -30,6 +30,7 @@ public partial class WebViewHandler : IWebViewHandler
[nameof(WebView.Settings)] = MapWebViewSettings
#elif __IOS__
[nameof(WKUIDelegate)] = MapWKUIDelegate,
+ [nameof(IWebView.Background)] = MapBackground,
#endif
};
diff --git a/src/Core/src/Handlers/WebView/WebViewHandler.iOS.cs b/src/Core/src/Handlers/WebView/WebViewHandler.iOS.cs
index d6d7da2d3dc2..7d7b83f0a58f 100644
--- a/src/Core/src/Handlers/WebView/WebViewHandler.iOS.cs
+++ b/src/Core/src/Handlers/WebView/WebViewHandler.iOS.cs
@@ -25,7 +25,15 @@ protected override WKWebView CreatePlatformView() =>
public static void MapWKUIDelegate(IWebViewHandler handler, IWebView webView)
{
if (handler is WebViewHandler platformHandler)
+ {
handler.PlatformView.UIDelegate = platformHandler._delegate ??= new MauiWebViewUIDelegate(handler);
+ }
+ }
+
+ static void MapBackground(IWebViewHandler handler, IWebView webView)
+ {
+ handler.PlatformView.Opaque = webView.Background is null;
+ handler.PlatformView.UpdateBackground(webView);
}
public static void MapSource(IWebViewHandler handler, IWebView webView)
diff --git a/src/Core/src/Platform/iOS/ViewExtensions.cs b/src/Core/src/Platform/iOS/ViewExtensions.cs
index c4a03a230963..0d5fb61fff6f 100644
--- a/src/Core/src/Platform/iOS/ViewExtensions.cs
+++ b/src/Core/src/Platform/iOS/ViewExtensions.cs
@@ -281,6 +281,11 @@ static void UpdateBackgroundLayers(this CALayer[] layers, string layerName, CGRe
/// Stops when it reaches the page view or a scrollable area, including .
///
public static void InvalidateMeasure(this UIView platformView, IView view)
+ {
+ InvalidateMeasure(platformView);
+ }
+
+ internal static void InvalidateMeasure(this UIView platformView)
{
if (platformView is IPlatformMeasureInvalidationController mauiPlatformView)
{
diff --git a/src/Templates/src/templates/maui-mobile/MauiApp.1.csproj b/src/Templates/src/templates/maui-mobile/MauiApp.1.csproj
index 3654b411d858..fc5eaf334d69 100644
--- a/src/Templates/src/templates/maui-mobile/MauiApp.1.csproj
+++ b/src/Templates/src/templates/maui-mobile/MauiApp.1.csproj
@@ -1,4 +1,4 @@
-
+
DOTNET_TFM-android;DOTNET_TFM-ios;DOTNET_TFM-maccatalyst
@@ -82,7 +82,11 @@
+
+
+
+
diff --git a/src/Templates/src/templates/maui-mobile/Pages/MainPage.xaml b/src/Templates/src/templates/maui-mobile/Pages/MainPage.xaml
index 60474f31d7da..24d7317fd143 100644
--- a/src/Templates/src/templates/maui-mobile/Pages/MainPage.xaml
+++ b/src/Templates/src/templates/maui-mobile/Pages/MainPage.xaml
@@ -8,16 +8,20 @@
xmlns:toolkit="http://schemas.microsoft.com/dotnet/2022/maui/toolkit"
x:Class="MauiApp._1.Pages.MainPage"
x:DataType="pageModels:MainPageModel"
+ x:Name="OverviewPage"
Title="{Binding Today}">
diff --git a/src/Templates/src/templates/maui-mobile/Pages/ManageMetaPage.xaml b/src/Templates/src/templates/maui-mobile/Pages/ManageMetaPage.xaml
index 9da452a884fa..27173ea943fd 100644
--- a/src/Templates/src/templates/maui-mobile/Pages/ManageMetaPage.xaml
+++ b/src/Templates/src/templates/maui-mobile/Pages/ManageMetaPage.xaml
@@ -6,11 +6,12 @@
xmlns:toolkit="http://schemas.microsoft.com/dotnet/2022/maui/toolkit"
x:DataType="pageModels:ManageMetaPageModel"
x:Class="MauiApp._1.Pages.ManageMetaPage"
+ x:Name="MetaPage"
Title="Categories and Tags">
-
@@ -61,7 +62,11 @@
Flags="ValidateOnUnfocusing"
+
+ Flags="ValidateOnUnfocused"
+
RegexPattern="^#(?:[0-9a-fA-F]{3}){1,2}$" />
@@ -103,7 +108,11 @@
Flags="ValidateOnUnfocusing"
+
+ Flags="ValidateOnUnfocused"
+
RegexPattern="^#(?:[0-9a-fA-F]{3}){1,2}$" />
diff --git a/src/TestUtils/src/Microsoft.Maui.IntegrationTests/Utilities/BuildWarningsUtilities.cs b/src/TestUtils/src/Microsoft.Maui.IntegrationTests/Utilities/BuildWarningsUtilities.cs
index 8d651fe9786b..e865e5e8db4a 100644
--- a/src/TestUtils/src/Microsoft.Maui.IntegrationTests/Utilities/BuildWarningsUtilities.cs
+++ b/src/TestUtils/src/Microsoft.Maui.IntegrationTests/Utilities/BuildWarningsUtilities.cs
@@ -126,25 +126,7 @@ public static void AssertWarnings(this List actualWarnings, Lis
#region Expected warning messages
// IMPORTANT: Always store expected File information as a relative path to the repo ROOT
- private static readonly List expectedNativeAOTWarnings = new()
- {
- // NOTE: this one is only expected when rooting all assemblies
- new WarningsPerFile
- {
- File = "/_/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/EnumConverterFactory.cs",
- WarningsPerCode = new List
- {
- new WarningsPerCode
- {
- Code = "IL3050",
- Messages = new List
- {
- "System.Text.Json.Serialization.Converters.EnumConverterFactory.CreateConverter(Type,JsonSerializerOptions): Using member 'System.Text.Json.Serialization.Converters.EnumConverterFactory.Create(Type,EnumConverterOptions,JsonNamingPolicy,JsonSerializerOptions)' which has 'RequiresDynamicCodeAttribute' can break functionality when AOT compiling. JSON serialization and deserialization might require types that cannot be statically analyzed and might need runtime code generation. Use System.Text.Json source generation for native AOT applications.",
- }
- },
- }
- },
- };
+ private static readonly List expectedNativeAOTWarnings = new();
#region Utility methods for generating the list of expected warnings