diff --git a/docs/specs/XamlXCode.md b/docs/specs/XamlXCode.md
deleted file mode 100644
index 4db3d7269c09..000000000000
--- a/docs/specs/XamlXCode.md
+++ /dev/null
@@ -1,221 +0,0 @@
-# XAML x:Code Directive
-
-## Overview
-
-The `x:Code` directive allows embedding inline C# member declarations directly in XAML files. The XAML source generator extracts these code blocks and emits them as part of a partial class, making them available alongside the code-behind.
-
-### Motivation
-
-Currently, any C# logic associated with a XAML page must live in a separate code-behind file. For simple cases — a single event handler, a helper method, a field — switching between XAML and code-behind adds friction. `x:Code` lets developers keep tightly-coupled logic next to the markup that uses it:
-
-- Small event handlers can live next to the control they serve
-- Helper methods used by a single page don't need a separate file
-- Prototyping is faster when everything is in one file
-
-### Example
-
-```xml
-
-
-
-
-
-
-```
-
-## Syntax
-
-### Basic Form
-
-`x:Code` is an element in the XAML `x:` namespace. Its text content is C# code:
-
-```xml
-
-```
-
-**CDATA is recommended** to avoid XML escaping issues with `<`, `>`, `&`, and other characters common in C#. Plain text content is also accepted for simple declarations that don't use these characters.
-
-### Placement Rules
-
-- `x:Code` **must be a direct child of the root element**. It cannot appear inside a `StackLayout`, `Grid`, or any other non-root element.
-- The root element **must have `x:Class`** defined — `x:Code` generates a partial class and needs a target type.
-- Multiple `x:Code` blocks are allowed. They are concatenated in document order.
-
-```xml
-
-
-
-
- _count++; ]]>
-
-
-
-
-
-
-
-
-
-
-
-
-
-```
-
-### What Can Go Inside x:Code
-
-`x:Code` accepts any C# that is valid inside a class body **or** at the file top level:
-
-| Supported | Example |
-|-----------|---------|
-| Methods | `void OnClicked(object s, EventArgs e) { }` |
-| Fields | `int _count;` |
-| Properties | `public string Name { get; set; }` |
-| Events | `public event EventHandler MyEvent;` |
-| Nested types | `record Item(string Name, int Qty);` |
-| Using directives | `using System.Net.Http;` |
-
-## Using Directives
-
-`using` directives inside `x:Code` are automatically promoted to the top of the generated file, outside the namespace and class declarations. This lets you reference additional namespaces from your inline code without modifying the code-behind.
-
-```xml
- FetchAsync()
- {
- using var client = new HttpClient();
- return await client.GetStringAsync("https://example.com");
- }
-
- double Clamp(double value) => Max(0, Min(1, value));
-]]>
-```
-
-**Generated output** (simplified):
-
-```csharp
-using System.Net.Http;
-using System.Threading.Tasks;
-using static System.Math;
-using Compat = System.ComponentModel;
-
-namespace MyApp
-{
- partial class MainPage
- {
- async Task FetchAsync()
- {
- using var client = new HttpClient();
- return await client.GetStringAsync("https://example.com");
- }
-
- double Clamp(double value) => Max(0, Min(1, value));
- }
-}
-```
-
-### Rules
-
-- **Regular usings** (`using System.Net.Http;`), **static usings** (`using static System.Math;`), and **aliases** (`using Alias = System.Type;`) are all promoted.
-- **Using statements** (`using var x = ...`, `using (var x = ...) { }`) are left inside the class body — they are runtime constructs, not directives.
-- **Duplicates are deduplicated.** If multiple `x:Code` blocks declare the same `using`, it appears once in the output.
-- Using directives from `x:Code` are **independent** of usings in the code-behind file. Each generated file has its own set.
-
-## Code Generation
-
-### Pipeline Position
-
-`x:Code` is processed as a third source generator pipeline, running between CodeBehind (CB) and InitializeComponent (IC):
-
-```
-XAML → CB pipeline → x:Code pipeline → IC pipeline
-```
-
-This ordering ensures:
-1. The code-behind partial class exists before x:Code is emitted
-2. Types and members declared in x:Code are visible to InitializeComponent (e.g., event handlers referenced in XAML attributes)
-
-### Output
-
-For each XAML file containing `x:Code`, the generator emits a source file with the hint name `{path}_{FileName}.xaml.xcode.cs` containing:
-
-1. Auto-generated header comment
-2. Promoted `using` directives (if any)
-3. A `namespace` block matching the `x:Class` namespace
-4. A `partial class` matching the `x:Class` type name
-5. The member code from all `x:Code` blocks, concatenated in document order
-
-### IC Visitor Behavior
-
-All InitializeComponent visitors (`CreateValuesVisitor`, `SetPropertiesVisitor`, `SetNamescopesAndRegisterNames`, etc.) skip `x:Code` elements entirely. The `x:Code` element is not treated as a XAML visual element — it produces no runtime object.
-
-## Diagnostics
-
-| Code | Severity | Condition |
-|------|----------|-----------|
-| MAUIX2012 | Error | `EnablePreviewFeatures` is not set (shared with XEXPR) |
-| MAUIX2015 | Error | `x:Code` is not a direct child of the root element |
-| MAUIX2016 | Error | `x:Code` used without `x:Class` on the root element |
-
-Standard C# compiler errors apply to the content of `x:Code` blocks (e.g., syntax errors, type resolution failures). These appear as normal build errors referencing the generated `.xcode.cs` file.
-
-## Constraints
-
-- **SourceGen only** — `x:Code` is not supported by Runtime inflation or XamlC. Attempting to use it with those inflators throws `NotSupportedException`.
-- **Requires `EnablePreviewFeatures`** — same gate as XAML C# Expressions (XEXPR).
-- **Root children only** — `x:Code` must be an immediate child of the root element.
-- **No access to x:Name fields** — `x:Code` is emitted in a separate partial class file. Fields generated by `x:Name` are in the InitializeComponent file. Both are partial, so members are accessible at compile time, but initialization order means `x:Name` fields are only populated after `InitializeComponent()` runs.
-
-## Relationship to XAML C# Expressions (XEXPR)
-
-`x:Code` and XEXPR are complementary features:
-
-| | XEXPR | x:Code |
-|-|-------|--------|
-| **Scope** | Inline expressions in attribute values | Member declarations in the class body |
-| **Syntax** | `{expression}` in attributes | `` element with C# code |
-| **Produces** | Bindings, event wiring, computed values | Methods, fields, properties, nested types |
-| **Use case** | Bind `{Price * Quantity}` or `{(s,e) => Save()}` | Define `void Save() { ... }` |
-
-They share the same prerequisites (`EnablePreviewFeatures`, SourceGen) and can be used together:
-
-```xml
-
- n <= 1 ? 1 : n * Factorial(n - 1);
- ]]>
-
-
-
-```
-
-## WPF Parity
-
-The `x:Code` directive originates from the [XAML 2006 specification](https://learn.microsoft.com/en-us/dotnet/desktop/xaml-services/xcode-intrinsic-xaml-type) and was supported in WPF. The .NET MAUI implementation follows the same core semantics with these differences:
-
-| Aspect | WPF | .NET MAUI |
-|--------|-----|-----------|
-| Processing | Runtime compilation | Source generator (compile-time) |
-| Inflator | Runtime only | SourceGen only |
-| Using directives | Not supported | ✅ Promoted to file top |
-| Preview gate | None | Requires `EnablePreviewFeatures` |
-| CDATA requirement | Required | Recommended (plain text also works) |
diff --git a/eng/pipelines/ci-official.yml b/eng/pipelines/ci-official.yml
index 4fa55bb22840..ee7812b2d540 100644
--- a/eng/pipelines/ci-official.yml
+++ b/eng/pipelines/ci-official.yml
@@ -104,7 +104,6 @@ extends:
onlyAndroidPlatformDefaultApis: true
skipAndroidEmulatorImages: true
skipAndroidCreateAvds: true
- skipSimulatorSetup: true
skipProvisioning: true
skipXcode: false
base64Encode: true
diff --git a/src/Controls/samples/Controls.Sample/Pages/Controls/MapsGalleries/MapPinsGallery.xaml b/src/Controls/samples/Controls.Sample/Pages/Controls/MapsGalleries/MapPinsGallery.xaml
index 25f2ecbe8ea0..b426e209a164 100644
--- a/src/Controls/samples/Controls.Sample/Pages/Controls/MapsGalleries/MapPinsGallery.xaml
+++ b/src/Controls/samples/Controls.Sample/Pages/Controls/MapsGalleries/MapPinsGallery.xaml
@@ -15,9 +15,6 @@
Text="Add Pin"
Clicked="OnAddPinClicked" />
-
0)
@@ -107,34 +100,13 @@ void OnAdd10PinsClicked(object sender, EventArgs e)
void AddPin()
{
- var randomLocation = GetRandomLocation();
- var pin = new Pin
+ pinsMap.Pins.Add(new Pin()
{
Label = $"Location {_locationIncrement++}",
- Location = randomLocation,
- };
- pinsMap.Pins.Add(pin);
- MoveMapTo(randomLocation);
- }
-
- void MovePin()
- {
- if (pinsMap.Pins.Count == 0)
- {
- return;
- }
-
- var randomLocation = GetRandomLocation();
- pinsMap.Pins[0].Location = randomLocation;
- MoveMapTo(randomLocation);
+ Location = _randomLocations[_locationRandomSeed.Next(0, _randomLocations.Length)],
+ });
}
- Position GetRandomLocation() =>
- _randomLocations[_locationRandomSeed.Next(_randomLocations.Length)];
-
- void MoveMapTo(Position location) =>
- pinsMap.MoveToRegion(MapSpan.FromCenterAndRadius(location, Distance.FromKilometers(DefaultMapRadiusKm)));
-
void OnMapClicked(object sender, MapClickedEventArgs e)
{
DisplayAlertAsync("Map", $"Map {e.Location.Latitude}, {e.Location.Longitude} clicked.", "Ok");
diff --git a/src/Controls/src/Core/BindableObject.cs b/src/Controls/src/Core/BindableObject.cs
index e1b2d409257c..60c66b8d2176 100644
--- a/src/Controls/src/Core/BindableObject.cs
+++ b/src/Controls/src/Core/BindableObject.cs
@@ -6,7 +6,6 @@
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
using Microsoft.Extensions.Logging;
using Microsoft.Maui.Controls.Internals;
using Microsoft.Maui.Dispatching;
@@ -39,8 +38,8 @@ public BindableObject()
}
internal ushort _triggerCount = 0;
- internal Dictionary _triggerSpecificity = new();
- readonly Dictionary _properties = new(4);
+ internal Dictionary _triggerSpecificity = new Dictionary();
+ readonly Dictionary _properties = new Dictionary(4);
bool _applying;
WeakReference _inheritedContext;
@@ -173,19 +172,66 @@ public object GetValue(BindableProperty property)
return context == null ? property.DefaultValue : context.Values.GetValue();
}
+ internal LocalValueEnumerator GetLocalValueEnumerator() => new LocalValueEnumerator(this);
+
+ internal sealed class LocalValueEnumerator : IEnumerator
+ {
+ Dictionary.Enumerator _propertiesEnumerator;
+ internal LocalValueEnumerator(BindableObject bindableObject) => _propertiesEnumerator = bindableObject._properties.GetEnumerator();
+
+ object IEnumerator.Current => Current;
+ public LocalValueEntry Current { get; private set; }
+
+ public bool MoveNext()
+ {
+ if (_propertiesEnumerator.MoveNext())
+ {
+ Current = new LocalValueEntry(_propertiesEnumerator.Current.Key, _propertiesEnumerator.Current.Value.Values.GetValue(), _propertiesEnumerator.Current.Value.Attributes);
+ return true;
+ }
+ return false;
+ }
+
+ public void Dispose() => _propertiesEnumerator.Dispose();
+
+ void IEnumerator.Reset()
+ {
+ ((IEnumerator)_propertiesEnumerator).Reset();
+ Current = null;
+ }
+ }
+
+ internal sealed class LocalValueEntry
+ {
+ internal LocalValueEntry(BindableProperty property, object value, BindableContextAttributes attributes)
+ {
+ Property = property;
+ Value = value;
+ Attributes = attributes;
+ }
+
+ public BindableProperty Property { get; }
+ public object Value { get; }
+ public BindableContextAttributes Attributes { get; }
+ }
+
internal (bool IsSet, T Value)[] GetValues(BindableProperty[] propArray)
{
- var properties = _properties;
+ Dictionary properties = _properties;
var resultArray = new (bool IsSet, T Value)[propArray.Length];
for (int i = 0; i < propArray.Length; i++)
{
- ref var result = ref resultArray[i];
- if (properties.TryGetValue(propArray[i].InternalId, out var context))
+ if (properties.TryGetValue(propArray[i], out var context))
{
var pair = context.Values.GetSpecificityAndValue();
- result.IsSet = pair.Key != SetterSpecificity.DefaultValue;
- result.Value = (T)pair.Value;
+ resultArray[i].IsSet = pair.Key != SetterSpecificity.DefaultValue;
+ resultArray[i].Value = (T)pair.Value;
+ }
+ else
+ {
+ resultArray[i].IsSet = false;
+ resultArray[i].Value = default(T);
}
}
@@ -703,7 +749,7 @@ static void BindingContextPropertyChanged(BindableObject bindable, object oldval
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- BindablePropertyContext CreateContext(BindableProperty property)
+ BindablePropertyContext CreateAndAddContext(BindableProperty property)
{
var defaultValueCreator = property.DefaultValueCreator;
var context = new BindablePropertyContext { Property = property };
@@ -712,31 +758,15 @@ BindablePropertyContext CreateContext(BindableProperty property)
if (defaultValueCreator != null)
context.Attributes = BindableContextAttributes.IsDefaultValueCreated;
+ _properties.Add(property, context);
return context;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- internal BindablePropertyContext GetContext(BindableProperty property) => _properties.TryGetValue(property.InternalId, out var result) ? result : null;
+ internal BindablePropertyContext GetContext(BindableProperty property) => _properties.TryGetValue(property, out var result) ? result : null;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- BindablePropertyContext GetOrCreateContext(BindableProperty property)
- {
-#if NETSTANDARD
- var context = GetContext(property);
- if (context is null)
- {
- context = CreateContext(property);
- _properties.Add(property.InternalId, context);
- }
-#else
- ref var context = ref CollectionsMarshal.GetValueRefOrAddDefault(_properties, property.InternalId, out var exists);
- if (!exists)
- {
- context = CreateContext(property);
- }
-#endif
- return context;
- }
+ BindablePropertyContext GetOrCreateContext(BindableProperty property) => GetContext(property) ?? CreateAndAddContext(property);
void RemoveBinding(BindableProperty property, BindablePropertyContext context, SetterSpecificity specificity)
{
diff --git a/src/Controls/src/Core/BindableProperty.cs b/src/Controls/src/Core/BindableProperty.cs
index 371446d3bb1b..31e0fc7bbf31 100644
--- a/src/Controls/src/Core/BindableProperty.cs
+++ b/src/Controls/src/Core/BindableProperty.cs
@@ -6,7 +6,6 @@
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Reflection;
-using System.Threading;
using Microsoft.Maui.Controls.Xaml;
using Microsoft.Maui.Graphics;
using Microsoft.Maui.Graphics.Converters;
@@ -182,9 +181,6 @@ public sealed class BindableProperty
/// A sentinel object used to indicate that a BindableProperty value has not been set.
public static readonly object UnsetValue = new object();
- private static int _nextInternalId = int.MinValue;
- internal readonly int InternalId;
-
BindableProperty(string propertyName, [DynamicallyAccessedMembers(ReturnTypeMembers)] Type returnType, [DynamicallyAccessedMembers(DeclaringTypeMembers)] Type declaringType, object defaultValue, BindingMode defaultBindingMode = BindingMode.OneWay,
ValidateValueDelegate validateValue = null, BindingPropertyChangedDelegate propertyChanged = null, BindingPropertyChangingDelegate propertyChanging = null,
CoerceValueDelegate coerceValue = null, BindablePropertyBindingChanging bindingChanging = null, bool isReadOnly = false, CreateDefaultValueDelegate defaultValueCreator = null)
@@ -195,8 +191,6 @@ public sealed class BindableProperty
throw new ArgumentNullException(nameof(returnType));
if (declaringType is null)
throw new ArgumentNullException(nameof(declaringType));
-
- InternalId = Interlocked.Increment(ref _nextInternalId);
// don't use Enum.IsDefined as its redonkulously expensive for what it does
if (defaultBindingMode != BindingMode.Default && defaultBindingMode != BindingMode.OneWay && defaultBindingMode != BindingMode.OneWayToSource && defaultBindingMode != BindingMode.TwoWay && defaultBindingMode != BindingMode.OneTime)
diff --git a/src/Controls/src/Core/Compatibility/Handlers/Shell/iOS/ShellTableViewController.cs b/src/Controls/src/Core/Compatibility/Handlers/Shell/iOS/ShellTableViewController.cs
index fee6f50e0e9c..dac39312fcbc 100644
--- a/src/Controls/src/Core/Compatibility/Handlers/Shell/iOS/ShellTableViewController.cs
+++ b/src/Controls/src/Core/Compatibility/Handlers/Shell/iOS/ShellTableViewController.cs
@@ -109,7 +109,6 @@ internal class AccessibilityNeutralTableView : UITableView, IUIAccessibilityCont
public AccessibilityNeutralTableView()
{
this.SetAccessibilityContainerType(UIAccessibilityContainerType.None);
- ScrollsToTop = false;
}
}
diff --git a/src/Controls/src/Core/Handlers/Items/Android/MauiCarouselRecyclerView.cs b/src/Controls/src/Core/Handlers/Items/Android/MauiCarouselRecyclerView.cs
index c3e62cbbbb90..24b18159ca99 100644
--- a/src/Controls/src/Core/Handlers/Items/Android/MauiCarouselRecyclerView.cs
+++ b/src/Controls/src/Core/Handlers/Items/Android/MauiCarouselRecyclerView.cs
@@ -18,7 +18,6 @@ public class MauiCarouselRecyclerView : MauiRecyclerView _oldViews;
CarouselViewOnGlobalLayoutListener _carouselViewLayoutListener;
@@ -224,9 +223,6 @@ void CollectionItemsSourceChanged(object sender, System.Collections.Specialized.
if (!(ItemsViewAdapter.ItemsSource is IItemsViewSource observableItemsSource))
return;
- // Set flag to disable animation during collection changes
- _isInternalPositionUpdate = true;
-
var carouselPosition = Carousel.Position;
var currentItemPosition = observableItemsSource.GetPosition(Carousel.CurrentItem);
var count = observableItemsSource.Count;
@@ -271,7 +267,6 @@ void CollectionItemsSourceChanged(object sender, System.Collections.Specialized.
if (removingAnyPrevious)
{
- _isInternalPositionUpdate = false;
return;
}
@@ -299,32 +294,23 @@ void CollectionItemsSourceChanged(object sender, System.Collections.Specialized.
GetDispatcher()
.Dispatch(() =>
{
- try
+ // If someone called explicit ScrollTo before the dispatched
+ // callback was delivered then don't override it.
+ if (_scrollToCounter == savedScrollToCounter)
{
- // If someone called explicit ScrollTo before the dispatched
- // callback was delivered then don't override it.
- if (_scrollToCounter == savedScrollToCounter)
- {
- SetCurrentItem(carouselPosition);
- UpdatePosition(carouselPosition);
- //If we are adding or removing the last item we need to update
- //the inset that we give to items so they are centered
- if (e.NewStartingIndex == count - 1 || removingLastElement)
- {
- UpdateItemDecoration();
- }
-
- UpdateVisualStates();
-
- ScrollToPosition(carouselPosition);
- }
+ SetCurrentItem(carouselPosition);
+ UpdatePosition(carouselPosition);
+ ScrollToPosition(carouselPosition);
}
- finally
+
+ //If we are adding or removing the last item we need to update
+ //the inset that we give to items so they are centered
+ if (e.NewStartingIndex == count - 1 || removingLastElement)
{
- // Reset flag after collection operations complete,
- // always reset even if ScrollTo was called or an exception occurred
- _isInternalPositionUpdate = false;
+ UpdateItemDecoration();
}
+
+ UpdateVisualStates();
});
}
@@ -464,11 +450,6 @@ void CarouselViewScrolled(object sender, ItemsViewScrolledEventArgs e)
if (!_initialized || !_isVisible)
return;
- // Do not process scroll events triggered by internal collection changes
- // (e.g. item inserted at index 0 shifts RecyclerView scroll offset)
- if (_isInternalPositionUpdate)
- return;
-
_noNeedForScroll = false;
var index = e.CenterItemIndex;
if (Carousel?.Loop == true)
@@ -529,7 +510,7 @@ void IMauiCarouselRecyclerView.UpdateFromCurrentItem()
if (_gotoPosition == -1 && currentItemPosition != carouselPosition)
{
_gotoPosition = currentItemPosition;
- ScrollToItemPosition(currentItemPosition, Carousel.AnimateCurrentItemChanges);
+ ItemsView.ScrollTo(currentItemPosition, position: Microsoft.Maui.Controls.ScrollToPosition.Center, animate: Carousel.AnimateCurrentItemChanges);
}
}
@@ -550,6 +531,7 @@ void IMauiCarouselRecyclerView.UpdateFromPosition()
return;
}
+
if (carouselPosition >= itemCount || carouselPosition < 0)
throw new IndexOutOfRangeException($"Can't set CarouselView to position {carouselPosition}. ItemsSource has {itemCount} items.");
@@ -566,21 +548,12 @@ void IMauiCarouselRecyclerView.UpdateFromPosition()
if (_gotoPosition == -1 && !Carousel.IsDragging && !Carousel.IsScrolling && centerPosition != carouselPosition)
{
_gotoPosition = carouselPosition;
- ScrollToItemPosition(carouselPosition, Carousel.AnimatePositionChanges);
+
+ ItemsView.ScrollTo(carouselPosition, position: Microsoft.Maui.Controls.ScrollToPosition.Center, animate: Carousel.AnimatePositionChanges);
}
SetCurrentItem(carouselPosition);
}
- void ScrollToItemPosition(int position, bool shouldAnimate)
- {
- if (position < 0 || position >= (ItemsViewAdapter?.ItemsSource?.Count ?? 0))
- return;
-
- // Disable animation during collection changes to prevent cascading scroll events
- var animate = shouldAnimate && !_isInternalPositionUpdate;
- ItemsView.ScrollTo(position, position: Microsoft.Maui.Controls.ScrollToPosition.Center, animate: animate);
- }
-
void AddLayoutListener()
{
if (_carouselViewLayoutListener is not null)
diff --git a/src/Controls/src/Core/Handlers/Items/Android/TemplatedItemViewHolder.cs b/src/Controls/src/Core/Handlers/Items/Android/TemplatedItemViewHolder.cs
index 3daa8149ddd7..184d53455b63 100644
--- a/src/Controls/src/Core/Handlers/Items/Android/TemplatedItemViewHolder.cs
+++ b/src/Controls/src/Core/Handlers/Items/Android/TemplatedItemViewHolder.cs
@@ -43,10 +43,13 @@ public void Recycle(ItemsView itemsView)
itemsView.RemoveLogicalChild(View);
- // Disconnect the current handler and release the platform content. We keep the
- // existing View/_selectedTemplate references so the next Bind() can decide whether
- // it needs to re-realize the same templated view or create a new one.
+ // Disconnect and clear the handler via ItemContentView.Recycle(), which calls
+ // DisconnectHandlers() before releasing Content. Reset _selectedTemplate so the
+ // next Bind() call always goes through the templateChanging path and recreates
+ // the handler (since we just disconnected it).
_itemContentView.Recycle();
+ View = null; // clear reference to the disconnected view
+ _selectedTemplate = null; // force templateChanging=true on next Bind() to recreate the view
}
public void Bind(object itemBindingContext, ItemsView itemsView,
@@ -87,16 +90,8 @@ public void Bind(object itemBindingContext, ItemsView itemsView,
if (!templateChanging)
{
- // Same template — update binding context. If the handler was disconnected
- // during recycle, re-realize the existing view to reconnect platform content
- // without losing any runtime property changes (e.g. dynamic HeightRequest).
+ // Same template, new data
View.BindingContext = itemBindingContext;
-
- if (View?.Handler is null)
- {
- PropertyPropagationExtensions.PropagatePropertyChanged(null, View, itemsView);
- _itemContentView.RealizeContent(View, itemsView);
- }
}
itemsView.AddLogicalChild(View);
diff --git a/src/Controls/src/Core/Handlers/Items/CarouselViewHandler.Windows.cs b/src/Controls/src/Core/Handlers/Items/CarouselViewHandler.Windows.cs
index 6b08e60c658b..624a1db7025a 100644
--- a/src/Controls/src/Core/Handlers/Items/CarouselViewHandler.Windows.cs
+++ b/src/Controls/src/Core/Handlers/Items/CarouselViewHandler.Windows.cs
@@ -15,8 +15,6 @@
using WScrollMode = Microsoft.UI.Xaml.Controls.ScrollMode;
using WSnapPointsAlignment = Microsoft.UI.Xaml.Controls.Primitives.SnapPointsAlignment;
using WSnapPointsType = Microsoft.UI.Xaml.Controls.SnapPointsType;
-using WSetter = Microsoft.UI.Xaml.Setter;
-using WStyle = Microsoft.UI.Xaml.Style;
namespace Microsoft.Maui.Controls.Handlers.Items
{
@@ -28,7 +26,6 @@ public partial class CarouselViewHandler : ItemsViewHandler
WScrollBarVisibility? _verticalScrollBarVisibilityWithoutLoop;
Size _currentSize;
bool _isCarouselViewReady;
- bool _isInternalPositionUpdate;
int _gotoPosition = -1;
NotifyCollectionChangedEventHandler _collectionChanged;
readonly WeakNotifyCollectionChangedProxy _proxy = new();
@@ -168,8 +165,7 @@ ListViewBase CreateCarouselListLayout(ItemsLayoutOrientation layoutOrientation)
listView = new FormsListView()
{
Style = (UI.Xaml.Style)WApp.Current.Resources["HorizontalCarouselListStyle"],
- ItemsPanel = (ItemsPanelTemplate)WApp.Current.Resources["HorizontalListItemsPanel"],
- ItemContainerStyle = GetItemContainerStyle(true)
+ ItemsPanel = (ItemsPanelTemplate)WApp.Current.Resources["HorizontalListItemsPanel"]
};
ScrollViewer.SetHorizontalScrollBarVisibility(listView, WScrollBarVisibility.Auto);
@@ -179,8 +175,7 @@ ListViewBase CreateCarouselListLayout(ItemsLayoutOrientation layoutOrientation)
{
listView = new FormsListView()
{
- Style = (UI.Xaml.Style)WApp.Current.Resources["VerticalCarouselListStyle"],
- ItemContainerStyle = GetItemContainerStyle(false)
+ Style = (UI.Xaml.Style)WApp.Current.Resources["VerticalCarouselListStyle"]
};
ScrollViewer.SetHorizontalScrollBarVisibility(listView, WScrollBarVisibility.Disabled);
@@ -294,7 +289,7 @@ double GetItemWidth()
if (CarouselItemsLayout.Orientation == ItemsLayoutOrientation.Horizontal)
{
- itemWidth = ListViewBase.ActualWidth - ItemsView.PeekAreaInsets.Left - ItemsView.PeekAreaInsets.Right - ItemsView.ItemsLayout.ItemSpacing;
+ itemWidth = ListViewBase.ActualWidth - ItemsView.PeekAreaInsets.Left - ItemsView.PeekAreaInsets.Right;
}
return Math.Max(itemWidth, 0);
@@ -306,7 +301,7 @@ double GetItemHeight()
if (CarouselItemsLayout.Orientation == ItemsLayoutOrientation.Vertical)
{
- itemHeight = ListViewBase.ActualHeight - ItemsView.PeekAreaInsets.Top - ItemsView.PeekAreaInsets.Bottom - ItemsView.ItemsLayout.ItemSpacing;
+ itemHeight = ListViewBase.ActualHeight - ItemsView.PeekAreaInsets.Top - ItemsView.PeekAreaInsets.Bottom;
}
return Math.Max(itemHeight, 0);
@@ -339,7 +334,9 @@ bool IsValidPosition(int position)
void SetCarouselViewPosition(int position)
{
if (ItemCount == 0)
+ {
return;
+ }
if (!IsValidPosition(position))
return;
@@ -421,9 +418,7 @@ void UpdateCurrentItem()
return;
}
- // Disable animation during collection changes to prevent cascading scroll events
- var animate = ItemsView.AnimateCurrentItemChanges && !_isInternalPositionUpdate;
- ItemsView.ScrollTo(currentItemPosition, position: ScrollToPosition.Center, animate: animate);
+ ItemsView.ScrollTo(currentItemPosition, position: ScrollToPosition.Center, animate: ItemsView.AnimateCurrentItemChanges);
}
void UpdatePosition()
@@ -571,53 +566,34 @@ void OnScrollViewChanged(object sender, ScrollViewerViewChangedEventArgs e)
void OnCollectionItemsSourceChanged(object sender, NotifyCollectionChangedEventArgs e)
{
- // Set flag to disable animation during collection changes
- _isInternalPositionUpdate = true;
-
- try
- {
- var carouselPosition = ItemsView.Position;
- var currentItemPosition = GetItemPositionInCarousel(ItemsView.CurrentItem);
- var count = (sender as IList).Count;
-
- bool removingCurrentElement = currentItemPosition == -1;
- bool removingLastElement = e.OldStartingIndex == count;
- bool removingFirstElement = e.OldStartingIndex == 0;
- bool removingCurrentElementButNotFirst = removingCurrentElement && removingLastElement && ItemsView.Position > 0;
-
- if (removingCurrentElementButNotFirst)
- {
- carouselPosition = ItemsView.Position - 1;
- }
- else if (removingFirstElement && !removingCurrentElement)
- {
- carouselPosition = currentItemPosition;
- }
+ var carouselPosition = ItemsView.Position;
+ var currentItemPosition = GetItemPositionInCarousel(ItemsView.CurrentItem);
+ var count = (sender as IList).Count;
- // If we are adding a new item make sure to maintain the CurrentItemPosition
- else if (e.Action == NotifyCollectionChangedAction.Add
- && currentItemPosition != -1)
- {
- carouselPosition = currentItemPosition;
- }
+ bool removingCurrentElement = currentItemPosition == -1;
+ bool removingLastElement = e.OldStartingIndex == count;
+ bool removingFirstElement = e.OldStartingIndex == 0;
+ bool removingCurrentElementButNotFirst = removingCurrentElement && removingLastElement && ItemsView.Position > 0;
- if (ItemsView.ItemsUpdatingScrollMode == ItemsUpdatingScrollMode.KeepLastItemInView)
- {
- carouselPosition = count == 0 ? 0 : count - 1;
- }
- else if (ItemsView.ItemsUpdatingScrollMode == ItemsUpdatingScrollMode.KeepItemsInView)
- {
- carouselPosition = 0;
- }
+ if (removingCurrentElementButNotFirst)
+ {
+ carouselPosition = ItemsView.Position - 1;
- SetCarouselViewCurrentItem(carouselPosition);
- SetCarouselViewPosition(carouselPosition);
}
- finally
+ else if (removingFirstElement && !removingCurrentElement)
+ {
+ carouselPosition = currentItemPosition;
+ }
+
+ // If we are adding a new item make sure to maintain the CurrentItemPosition
+ else if (e.Action == NotifyCollectionChangedAction.Add
+ && currentItemPosition != -1)
{
- // Reset flag after collection operations complete
- _isInternalPositionUpdate = false;
+ carouselPosition = currentItemPosition;
}
+
+ SetCarouselViewCurrentItem(carouselPosition);
+ SetCarouselViewPosition(carouselPosition);
}
void OnListViewSizeChanged(object sender, SizeChangedEventArgs e) => Resize(e.NewSize);
@@ -663,15 +639,5 @@ void InvalidateItemSize()
item.ItemWidth = itemWidth;
}
}
-
- WStyle GetItemContainerStyle(bool isHorizontalLayout)
- {
- var h = CarouselItemsLayout?.ItemSpacing > 0 ? (CarouselItemsLayout.ItemSpacing) / 2 : 0;
- var padding = isHorizontalLayout ? WinUIHelpers.CreateThickness(h, 0, h, 0) : WinUIHelpers.CreateThickness(0, h, 0, h);
-
- var style = new WStyle(typeof(ListViewItem));
- style.Setters.Add(new WSetter(Control.PaddingProperty, padding));
- return style;
- }
}
}
diff --git a/src/Controls/src/Core/Handlers/Items2/iOS/CarouselViewController2.cs b/src/Controls/src/Core/Handlers/Items2/iOS/CarouselViewController2.cs
index 77368150476a..9e1b5549a4ce 100644
--- a/src/Controls/src/Core/Handlers/Items2/iOS/CarouselViewController2.cs
+++ b/src/Controls/src/Core/Handlers/Items2/iOS/CarouselViewController2.cs
@@ -16,7 +16,6 @@ public class CarouselViewController2 : ItemsViewController2
{
bool _isRotating = false;
bool _isUpdating = false;
- bool _isInternalCollectionUpdate = false;
int _section = 0;
bool _wasDetachedFromWindow = false;
CarouselViewLoopManager _carouselViewLoopManager;
@@ -210,7 +209,6 @@ void TearDown(CarouselView carouselView)
_carouselViewLoopManager = null;
_isUpdating = false;
_isRotating = false;
- _isInternalCollectionUpdate = false;
}
internal void UpdateScrollingConstraints()
@@ -315,21 +313,14 @@ void CollectionViewUpdating(object sender, NotifyCollectionChangedEventArgs e)
{
_positionAfterUpdate = GetPositionWhenAddingItems(carouselPosition, currentItemPosition);
}
-
- // Suppress any scroll-driven SetPosition calls that UIKit fires during the batch update
- _isInternalCollectionUpdate = true;
}
[UnconditionalSuppressMessage("Memory", "MEM0003", Justification = "Proven safe in test: MemoryTests.HandlerDoesNotLeak")]
void CollectionViewUpdated(object sender, NotifyCollectionChangedEventArgs e)
{
- // Clear before anything else so SetPosition/SetCurrentItem called from this method are not suppressed
- _isInternalCollectionUpdate = false;
-
int targetPosition;
if (_positionAfterUpdate == -1)
{
- _isUpdating = false;
return;
}
@@ -356,6 +347,7 @@ void CollectionViewUpdated(object sender, NotifyCollectionChangedEventArgs e)
}
}
+
_isUpdating = false;
ScrollToPosition(targetPosition, targetPosition, false, true);
}
@@ -366,7 +358,7 @@ int GetPositionWhenAddingItems(int carouselPosition, int currentItemPosition)
return currentItemPosition != -1 ? currentItemPosition : carouselPosition;
}
- int GetTargetPosition()
+ private int GetTargetPosition()
{
if (ItemsSource.ItemCount == 0)
{
@@ -488,12 +480,6 @@ void ScrollToPosition(int goToPosition, int carouselPosition, bool animate, bool
internal void SetPosition(int position)
{
- // Suppress spurious calls from UIKit scroll callbacks during a collection batch update
- if (_isInternalCollectionUpdate)
- {
- return;
- }
-
if (ItemsView is not CarouselView carousel)
{
return;
diff --git a/src/Controls/src/Core/Handlers/Items2/iOS/ItemsViewController2.cs b/src/Controls/src/Core/Handlers/Items2/iOS/ItemsViewController2.cs
index 05311537a7ab..a92f32bc467e 100644
--- a/src/Controls/src/Core/Handlers/Items2/iOS/ItemsViewController2.cs
+++ b/src/Controls/src/Core/Handlers/Items2/iOS/ItemsViewController2.cs
@@ -181,8 +181,6 @@ public override void ViewDidLoad()
CollectionView.ContentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentBehavior.Never;
}
- CollectionView.ScrollsToTop = true;
-
RegisterViewTypes();
EnsureLayoutInitialized();
diff --git a/src/Controls/src/Core/Handlers/Shell/Windows/ShellView.cs b/src/Controls/src/Core/Handlers/Shell/Windows/ShellView.cs
index b9b7d4714ec9..e686fe7005d3 100644
--- a/src/Controls/src/Core/Handlers/Shell/Windows/ShellView.cs
+++ b/src/Controls/src/Core/Handlers/Shell/Windows/ShellView.cs
@@ -287,10 +287,7 @@ ShellItemHandler CreateShellItemView()
return ItemRenderer;
}
- void TabSelectionChanged(NavigationView sender, NavigationViewSelectionChangedEventArgs args)
- {
+ void TabSelectionChanged(NavigationView sender, NavigationViewSelectionChangedEventArgs args) =>
Element?.Handler?.UpdateValue(nameof(Shell.CurrentItem));
- UpdateHeaderVisibility();
- }
}
}
diff --git a/src/Controls/src/Core/Platform/iOS/Extensions/LabelExtensions.cs b/src/Controls/src/Core/Platform/iOS/Extensions/LabelExtensions.cs
index b1680b9adc34..420072552a7f 100644
--- a/src/Controls/src/Core/Platform/iOS/Extensions/LabelExtensions.cs
+++ b/src/Controls/src/Core/Platform/iOS/Extensions/LabelExtensions.cs
@@ -1,7 +1,6 @@
#nullable disable
using Microsoft.Maui;
using Microsoft.Maui.Controls;
-using Microsoft.Maui.Controls.Handlers.Items2;
using Microsoft.Maui.Controls.Internals;
using ObjCRuntime;
using UIKit;
@@ -17,37 +16,22 @@ public static void UpdateText(this UILabel platformLabel, Label label)
switch (label.TextType)
{
case TextType.Html:
- // NOTE: Setting HTML text like this will crash with some sort of consistency error.
- // when inside a CV1 (CollectionView/CarouselView handler v1) layout pass.
+ // NOTE: Setting HTML text this will crash with some sort of consistency error.
// https://github.com/dotnet/maui/issues/25946
- // CV2 (the default handler in .NET 10) does NOT have this crash.
- if (IsPlatformLabelInsideCV2Cell(platformLabel))
+ // Here we have to dispatch back the the main queue to avoid the crash.
+ // This is observed with CarouselView 1 but not with 2, so hopefully this
+ // will be just disappear once we switch.
+ CoreFoundation.DispatchQueue.MainQueue.DispatchAsync(() =>
{
- // Synchronous: safe in CV2, avoids the two-pass jitter.
- // No InvalidateMeasure needed — text is already correct when measured.
platformLabel.UpdateTextHtml(text);
- if (label.Handler is LabelHandler labelHandlerSync)
- {
- Label.MapFormatting(labelHandlerSync, label);
- }
- }
- else
- {
- CoreFoundation.DispatchQueue.MainQueue.DispatchAsync(() =>
- {
- platformLabel.UpdateTextHtml(text);
-
- if (label.Handler is LabelHandler labelHandler)
- {
- Label.MapFormatting(labelHandler, label);
- }
+ if (label.Handler is LabelHandler labelHandler)
+ Label.MapFormatting(labelHandler, label);
- // NOTE: Because we are updating text outside the normal layout
- // pass, we need to invalidate the measure for the next pass.
- label.InvalidateMeasure();
- });
- }
+ // NOTE: Because we are updating text outside the normal layout
+ // pass, we need to invalidate the measure for the next pass.
+ label.InvalidateMeasure();
+ });
break;
default:
@@ -65,20 +49,5 @@ public static void UpdateText(this UILabel platformLabel, Label label)
break;
}
}
-
- // Walks the native UIKit superview chain to determine if this UILabel lives inside a CV2 cell.
- static bool IsPlatformLabelInsideCV2Cell(UILabel platformLabel)
- {
- var superview = platformLabel.Superview;
- while (superview is not null)
- {
- if (superview is ItemsViewCell2)
- {
- return true;
- }
- superview = superview.Superview;
- }
- return false;
- }
}
}
diff --git a/src/Controls/src/Core/RadioButton/RadioButtonGroup.cs b/src/Controls/src/Core/RadioButton/RadioButtonGroup.cs
index ecced42f2c03..24c799c8ecdf 100644
--- a/src/Controls/src/Core/RadioButton/RadioButtonGroup.cs
+++ b/src/Controls/src/Core/RadioButton/RadioButtonGroup.cs
@@ -79,15 +79,7 @@ internal static void UncheckOtherRadioButtonsInScope(RadioButton radioButton)
{
if (!string.IsNullOrEmpty(radioButton.GroupName))
{
- var root = GetVisualRoot(radioButton);
-
- // If no Page ancestor exists (e.g., during initial layout construction before the
- // layout is attached to a Page), fall back to the controller's layout element.
- // This ensures RadioButtons inside ContentView ControlTemplates are correctly found
- // and unchecked even before the visual tree has a Page root (fixes issue #34759).
- root ??= RadioButtonGroupController.GetGroupController(radioButton)?.Layout;
- root ??= (Element)radioButton.Parent;
-
+ var root = GetVisualRoot(radioButton) ?? radioButton.Parent;
if (root is not IElementController rootController)
{
return;
diff --git a/src/Controls/src/Core/RadioButton/RadioButtonGroupController.cs b/src/Controls/src/Core/RadioButton/RadioButtonGroupController.cs
index 443d4e146161..1bb69caaa5e7 100644
--- a/src/Controls/src/Core/RadioButton/RadioButtonGroupController.cs
+++ b/src/Controls/src/Core/RadioButton/RadioButtonGroupController.cs
@@ -11,8 +11,6 @@ internal class RadioButtonGroupController
string _groupName;
private object _selectedValue;
- internal Element Layout => _layout;
-
public string GroupName { get => _groupName; set => SetGroupName(value); }
public object SelectedValue { get => _selectedValue; set => SetSelectedValue(value); }
@@ -105,10 +103,7 @@ void AddRadioButton(RadioButton radioButton)
_layout.SetValue(RadioButtonGroup.SelectedValueProperty, radioButton.Value);
}
- // Only auto-check if SelectedValue is explicitly set (non-null).
- // When SelectedValue is null (no selection), adding a RadioButton whose Value is also
- // null must not cause it to be auto-checked (fixes issue #34759).
- if (this.SelectedValue is not null && object.Equals(radioButton.Value, this.SelectedValue))
+ if (object.Equals(radioButton.Value, this.SelectedValue))
{
radioButton.SetValue(RadioButton.IsCheckedProperty, true, specificity: SetterSpecificity.FromHandler);
}
diff --git a/src/Controls/src/Core/TabbedPage/TabbedPage.Windows.cs b/src/Controls/src/Core/TabbedPage/TabbedPage.Windows.cs
index 6c1d58093634..49ee36888e2d 100644
--- a/src/Controls/src/Core/TabbedPage/TabbedPage.Windows.cs
+++ b/src/Controls/src/Core/TabbedPage/TabbedPage.Windows.cs
@@ -203,10 +203,7 @@ void OnApplyTemplateFinished(object? sender, EventArgs e)
void OnNavigationViewSizeChanged(object sender, SizeChangedEventArgs e)
{
if (_navigationView != null)
- {
- this.InvalidateMeasure();
- this.Arrange(new Rect(0, 0, e.NewSize.Width, e.NewSize.Height));
- }
+ this.Arrange(_navigationView);
}
void SetupNavigationView()
diff --git a/src/Controls/src/SourceGen/AnalyzerReleases.Unshipped.md b/src/Controls/src/SourceGen/AnalyzerReleases.Unshipped.md
index 01079b48e10d..7618199f24cc 100644
--- a/src/Controls/src/SourceGen/AnalyzerReleases.Unshipped.md
+++ b/src/Controls/src/SourceGen/AnalyzerReleases.Unshipped.md
@@ -30,5 +30,3 @@ MAUIX2010 | XamlParsing | Info | ExpressionNotSettable
MAUIX2011 | XamlParsing | Warning | AmbiguousMemberWithStaticType
MAUIX2012 | XamlParsing | Error | CSharpExpressionsRequirePreviewFeatures
MAUIX2013 | XamlParsing | Error | AsyncLambdaNotSupported
-MAUIX2015 | XamlParsing | Error | XCodeNotChildOfRoot
-MAUIX2016 | XamlParsing | Error | XCodeRequiresXClass
diff --git a/src/Controls/src/SourceGen/Descriptors.cs b/src/Controls/src/SourceGen/Descriptors.cs
index 59e9af203571..fed3bdb7ba1d 100644
--- a/src/Controls/src/SourceGen/Descriptors.cs
+++ b/src/Controls/src/SourceGen/Descriptors.cs
@@ -317,23 +317,6 @@ public static class Descriptors
defaultSeverity: DiagnosticSeverity.Error,
isEnabledByDefault: true);
- // x:Code diagnostics
- public static DiagnosticDescriptor XCodeNotChildOfRoot = new DiagnosticDescriptor(
- id: "MAUIX2015",
- title: "x:Code must be an immediate child of the root element",
- messageFormat: "x:Code must be an immediate child of the root element.",
- category: "XamlParsing",
- defaultSeverity: DiagnosticSeverity.Error,
- isEnabledByDefault: true);
-
- public static DiagnosticDescriptor XCodeRequiresXClass = new DiagnosticDescriptor(
- id: "MAUIX2016",
- title: "x:Code requires x:Class on the root element",
- messageFormat: "x:Code requires x:Class to be specified on the root element.",
- category: "XamlParsing",
- defaultSeverity: DiagnosticSeverity.Error,
- isEnabledByDefault: true);
-
public static DiagnosticDescriptor MissingEventHandler = new DiagnosticDescriptor(
id: "MAUIX2014",
title: new LocalizableResourceString(nameof(MauiGResources.MissingEventHandlerTitle), MauiGResources.ResourceManager, typeof(MauiGResources)),
diff --git a/src/Controls/src/SourceGen/GeneratorHelpers.cs b/src/Controls/src/SourceGen/GeneratorHelpers.cs
index 445c74523bc7..24b34f85cec9 100644
--- a/src/Controls/src/SourceGen/GeneratorHelpers.cs
+++ b/src/Controls/src/SourceGen/GeneratorHelpers.cs
@@ -36,15 +36,6 @@ public static string EscapeIdentifier(string identifier)
: $"@{identifier}";
}
- ///
- /// Returns true if the node is an x:Code element, which is handled by the x:Code pipeline
- /// and should be ignored by IC visitors.
- ///
- internal static bool IsXCodeElement(INode node)
- => node is ElementNode en
- && en.XmlType.Name == "Code"
- && (en.NamespaceURI == XamlParser.X2006Uri || en.NamespaceURI == XamlParser.X2009Uri);
-
public static ProjectItem? ComputeProjectItem((AdditionalText additionalText, AnalyzerConfigOptionsProvider optionsProvider) tuple, CancellationToken cancellationToken)
{
if (cancellationToken.IsCancellationRequested)
@@ -165,80 +156,6 @@ internal static bool IsXCodeElement(INode node)
return new XamlProjectItemForCB(projectItem, root, nsmgr);
}
- ///
- /// Extracts x:Code blocks from a XAML file. Returns null if no x:Code elements are found
- /// or if the XAML doesn't meet the requirements (x:Class, EnablePreviewFeatures).
- ///
- public static (ProjectItem ProjectItem, string Source, List Diagnostics)? ComputeXCodeSource(
- (XamlProjectItemForCB?, AssemblyAttributes) input,
- CancellationToken cancellationToken)
- {
- var (xamlItem, xmlnsCache) = input;
- if (xamlItem?.Root == null || xamlItem.ProjectItem == null)
- return null;
-
- var root = xamlItem.Root;
- var nsmgr = xamlItem.Nsmgr;
- var projItem = xamlItem.ProjectItem;
- var diagnostics = new List();
-
- // Find all x:Code child elements of the root
- var codeBlocks = new List();
-
- foreach (XmlNode child in root.ChildNodes)
- {
- cancellationToken.ThrowIfCancellationRequested();
-
- if (child.LocalName != "Code")
- continue;
- if (child.NamespaceURI != XamlParser.X2006Uri && child.NamespaceURI != XamlParser.X2009Uri)
- continue;
-
- codeBlocks.Add(child.InnerText);
- }
-
- if (codeBlocks.Count == 0)
- return null;
-
- // Gate: EnablePreviewFeatures required
- if (!projItem.EnablePreviewFeatures)
- {
- if (projItem.RelativePath is string path)
- {
- var location = LocationHelpers.LocationCreate(path, new XmlLineInfo(), string.Empty);
- diagnostics.Add(Diagnostic.Create(Descriptors.CSharpExpressionsRequirePreviewFeatures, location));
- }
- return (projItem, string.Empty, diagnostics);
- }
-
- // Gate: x:Class must be present
- var rootClass = root.Attributes["Class", XamlParser.X2006Uri]
- ?? root.Attributes["Class", XamlParser.X2009Uri];
- if (rootClass == null)
- {
- if (projItem.RelativePath is string path)
- {
- var location = LocationHelpers.LocationCreate(path, new XmlLineInfo(), string.Empty);
- diagnostics.Add(Diagnostic.Create(Descriptors.XCodeRequiresXClass, location));
- }
- return (projItem, string.Empty, diagnostics);
- }
-
- XmlnsHelper.ParseXmlns(rootClass.Value, out var rootType, out var rootClrNamespace, out _, out _);
- if (rootType == null || rootClrNamespace == null)
- {
- if (projItem.RelativePath is string path)
- {
- var location = LocationHelpers.LocationCreate(path, new XmlLineInfo(), string.Empty);
- diagnostics.Add(Diagnostic.Create(Descriptors.XCodeRequiresXClass, location));
- }
- return (projItem, string.Empty, diagnostics);
- }
-
- var source = XCodeCodeWriter.GenerateXCode(rootClrNamespace, rootType, codeBlocks.ToArray());
- return (projItem, source, diagnostics);
- }
-
public static (XmlNode?, XmlNamespaceManager) LoadXmlDocument(SourceText text, AssemblyAttributes assemblyCaches, CancellationToken cancellationToken)
{
var nsmgr = new XmlNamespaceManager(new NameTable());
diff --git a/src/Controls/src/SourceGen/InitializeComponentCodeWriter.cs b/src/Controls/src/SourceGen/InitializeComponentCodeWriter.cs
index 660cb8d5b369..db94769a8e97 100644
--- a/src/Controls/src/SourceGen/InitializeComponentCodeWriter.cs
+++ b/src/Controls/src/SourceGen/InitializeComponentCodeWriter.cs
@@ -163,22 +163,8 @@ static void WriteMultiLineString(IndentedTextWriter writer, string text)
}
}
- ///
- /// Removes x:Code elements from the node tree. The x:Code pipeline has already
- /// extracted their content, so IC visitors should not see them.
- ///
- static void StripXCodeElements(RootNode rootnode)
- {
- for (int i = rootnode.CollectionItems.Count - 1; i >= 0; i--)
- {
- if (GeneratorHelpers.IsXCodeElement(rootnode.CollectionItems[i]))
- rootnode.CollectionItems.RemoveAt(i);
- }
- }
-
static void Visit(RootNode rootnode, SourceGenContext visitorContext, bool useDesignProperties = false)
{
- StripXCodeElements(rootnode);
rootnode.Accept(new XamlNodeVisitor((node, parent) => node.Parent = parent), null); //set parents for {StaticResource}
rootnode.Accept(new ExpandMarkupsVisitor(visitorContext), null);
rootnode.Accept(new PruneIgnoredNodesVisitor(useDesignProperties), null);
diff --git a/src/Controls/src/SourceGen/TrackingNames.cs b/src/Controls/src/SourceGen/TrackingNames.cs
index 3e6586615695..fe136ba84f6e 100644
--- a/src/Controls/src/SourceGen/TrackingNames.cs
+++ b/src/Controls/src/SourceGen/TrackingNames.cs
@@ -15,7 +15,5 @@ public class TrackingNames
public const string XamlSourceProviderForCB = nameof(XamlSourceProviderForCB);
public const string XamlSourceProviderForIC = nameof(XamlSourceProviderForIC);
public const string CompilationWithCodeBehindProvider = nameof(CompilationWithCodeBehindProvider);
- public const string XamlSourceProviderForXCode = nameof(XamlSourceProviderForXCode);
- public const string CompilationWithXCodeProvider = nameof(CompilationWithXCodeProvider);
public const string XmlnsDefinitionsProviderForIC = nameof(XmlnsDefinitionsProviderForIC);
}
diff --git a/src/Controls/src/SourceGen/Visitors/SetPropertiesVisitor.cs b/src/Controls/src/SourceGen/Visitors/SetPropertiesVisitor.cs
index 5fad80526648..29e57c245292 100644
--- a/src/Controls/src/SourceGen/Visitors/SetPropertiesVisitor.cs
+++ b/src/Controls/src/SourceGen/Visitors/SetPropertiesVisitor.cs
@@ -18,7 +18,6 @@ class SetPropertiesVisitor(SourceGenContext context, bool stopOnResourceDictiona
XmlName.xArguments,
XmlName.xClass,
XmlName.xClassModifier,
- XmlName.xCode,
XmlName.xDataType,
XmlName.xFactoryMethod,
XmlName.xFieldModifier,
diff --git a/src/Controls/src/SourceGen/XCodeCodeWriter.cs b/src/Controls/src/SourceGen/XCodeCodeWriter.cs
deleted file mode 100644
index 5e7c5855005a..000000000000
--- a/src/Controls/src/SourceGen/XCodeCodeWriter.cs
+++ /dev/null
@@ -1,69 +0,0 @@
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-
-using static Microsoft.Maui.Controls.SourceGen.GeneratorHelpers;
-
-namespace Microsoft.Maui.Controls.SourceGen;
-
-static class XCodeCodeWriter
-{
- public static string GenerateXCode(string rootClrNamespace, string rootType, string[] codeBlocks)
- {
- var usings = new List();
- var memberLines = new List();
-
- foreach (var block in codeBlocks)
- {
- foreach (var line in block.Replace("\r\n", "\n").Split('\n'))
- {
- var trimmed = line.Trim();
- if (IsUsingDirective(trimmed))
- usings.Add(trimmed);
- else
- memberLines.Add(line);
- }
- }
-
- var sb = new StringBuilder();
- sb.AppendLine(AutoGeneratedHeaderText);
- sb.AppendLine();
-
- foreach (var u in usings.Distinct())
- sb.AppendLine(u);
-
- if (usings.Count > 0)
- sb.AppendLine();
-
- sb.AppendLine($"namespace {rootClrNamespace}");
- sb.AppendLine("{");
- sb.AppendLine($"\tpartial class {rootType}");
- sb.AppendLine("\t{");
-
- foreach (var line in memberLines)
- sb.AppendLine(line);
-
- sb.AppendLine("\t}");
- sb.AppendLine("}");
-
- return sb.ToString();
- }
-
- ///
- /// Returns true if the line is a using directive (e.g. "using System;", "using static System.Math;",
- /// "using Alias = System.Type;") as opposed to a using statement ("using var x = ...", "using (...)").
- ///
- static bool IsUsingDirective(string trimmedLine)
- {
- if (!trimmedLine.StartsWith("using ", System.StringComparison.Ordinal) ||
- !trimmedLine.EndsWith(";", System.StringComparison.Ordinal))
- return false;
-
- var afterUsing = trimmedLine.Substring(6).TrimStart();
- if (afterUsing.StartsWith("var ", System.StringComparison.Ordinal) ||
- afterUsing.StartsWith("(", System.StringComparison.Ordinal))
- return false;
-
- return true;
- }
-}
diff --git a/src/Controls/src/SourceGen/XamlGenerator.cs b/src/Controls/src/SourceGen/XamlGenerator.cs
index 0ff3556ed33f..13cdb8d2bc18 100644
--- a/src/Controls/src/SourceGen/XamlGenerator.cs
+++ b/src/Controls/src/SourceGen/XamlGenerator.cs
@@ -88,41 +88,13 @@ public void Initialize(IncrementalGeneratorInitializationContext initContext)
})
.WithTrackingName(TrackingNames.CompilationWithCodeBehindProvider);
- // x:Code pipeline: extract x:Code blocks from XAML and emit as partial class
- var xamlSourceProviderForXCode = xamlProjectItemProviderForCB
- .Combine(xmlnsDefinitionsProvider)
- .Select(ComputeXCodeSource)
- .WithTrackingName(TrackingNames.XamlSourceProviderForXCode);
-
- // Feed x:Code into compilation (after CB, before IC)
- var compilationWithXCodeProvider = xamlSourceProviderForXCode
- .Collect()
- .Combine(compilationWithCodeBehindProvider)
- .Select(static (t, ct) =>
- {
- var compilation = t.Right;
- var options = compilation.SyntaxTrees.FirstOrDefault()?.Options as CSharpParseOptions;
- foreach (var item in t.Left)
- {
- ct.ThrowIfCancellationRequested();
-
- if (item is { } xcode && !string.IsNullOrEmpty(xcode.Source))
- {
- var tree = CSharpSyntaxTree.ParseText(xcode.Source, options: options, cancellationToken: ct);
- compilation = compilation.AddSyntaxTrees(tree);
- }
- }
- return compilation;
- })
- .WithTrackingName(TrackingNames.CompilationWithXCodeProvider);
-
- //this xmlnsDefinitionProvider is computed AFTER feeding the codebehind and x:Code into the compilation, and allows correct assemblySymbol comparisons
- var xmlnsDefinitionsProviderForIC = compilationWithXCodeProvider
+ //this xmlnsDefinitionProvider is computed AFTER feeding the codebehind into the compilation, and allows correct assemblySymbol comparisons
+ var xmlnsDefinitionsProviderForIC = compilationWithCodeBehindProvider
.Select(GetAssemblyAttributes)
.WithTrackingName(TrackingNames.XmlnsDefinitionsProviderForIC);
var xamlSourceProviderForIC = xamlProjectItemProviderForIC
- .Combine(xmlnsDefinitionsProviderForIC, compilationWithXCodeProvider.Select(GetTypeCache), compilationWithXCodeProvider)
+ .Combine(xmlnsDefinitionsProviderForIC, compilationWithCodeBehindProvider.Select(GetTypeCache), compilationWithCodeBehindProvider)
.WithTrackingName(TrackingNames.XamlSourceProviderForIC);
// Register the XAML pipeline for CodeBehind
@@ -164,19 +136,6 @@ public void Initialize(IncrementalGeneratorInitializationContext initContext)
}
});
- // Register the x:Code pipeline
- initContext.RegisterSourceOutput(xamlSourceProviderForXCode, static (sourceProductionContext, provider) =>
- {
- if (provider is not { } xcode)
- return;
-
- foreach (var diag in xcode.Diagnostics)
- sourceProductionContext.ReportDiagnostic(diag);
-
- if (!string.IsNullOrEmpty(xcode.Source))
- sourceProductionContext.AddSource(GetHintName(xcode.ProjectItem, "xcode"), xcode.Source);
- });
-
// Register the XAML pipeline for InitializeComponent
initContext.RegisterImplementationSourceOutput(xamlSourceProviderForIC, static (sourceProductionContext, provider) =>
{
diff --git a/src/Controls/src/Xaml/XmlName.cs b/src/Controls/src/Xaml/XmlName.cs
index ecd27f921304..25068f7d9352 100644
--- a/src/Controls/src/Xaml/XmlName.cs
+++ b/src/Controls/src/Xaml/XmlName.cs
@@ -16,7 +16,6 @@ internal readonly struct XmlName(string namespaceUri, string localName)
public static readonly XmlName xFieldModifier = new("x", "FieldModifier");
public static readonly XmlName xKey = new("x", "Key");
public static readonly XmlName xName = new("x", "Name");
- public static readonly XmlName xCode = new("x", "Code");
public static readonly XmlName xTypeArguments = new("x", "TypeArguments");
public static readonly XmlName mcIgnorable = new(XamlParser.McUri, "Ignorable");
public static readonly XmlName Empty = new();
diff --git a/src/Controls/tests/Core.UnitTests/RadioButtonTests.cs b/src/Controls/tests/Core.UnitTests/RadioButtonTests.cs
index a3ba8711cdff..27a83f3ea341 100644
--- a/src/Controls/tests/Core.UnitTests/RadioButtonTests.cs
+++ b/src/Controls/tests/Core.UnitTests/RadioButtonTests.cs
@@ -282,7 +282,7 @@ WeakReference CreateReference()
Assert.False(reference.IsAlive, "RadioButton should not be alive");
}
-
+
[Fact]
public void GroupNullSelectionClearsAnySelection()
{
@@ -409,87 +409,5 @@ public void RadioButtonGroupSelectedValueBindingWorksWithNestedDescendants()
Assert.False(radioButton2.IsChecked);
Assert.True(radioButton3.IsChecked);
}
-
- [Fact]
- public void RadioButtonGroupWorksWithContentViewControlTemplate()
- {
- // ContentView with ControlTemplate containing RadioButton
- // The ControlTemplate is applied inline (before ContentView is added to parent layout)
- var groupName = "Test1";
- var layout = new VerticalStackLayout();
- layout.SetValue(RadioButtonGroup.GroupNameProperty, groupName);
-
- // Create ContentView with inline ControlTemplate (RadioButton inside Border)
- // This mimics how XAML inline ControlTemplate works - template is applied
- // before ContentView is added to the parent layout
- var radioButton1 = new RadioButton { Content = "Option 1", Value = "opt1", GroupName = groupName };
- var radioButton2 = new RadioButton { Content = "Option 2", Value = "opt2", GroupName = groupName };
-
- var border1 = new Border { Content = radioButton1 };
- var border2 = new Border { Content = radioButton2 };
-
- var contentView1 = new ContentView();
- var contentView2 = new ContentView();
-
- // Apply ControlTemplate by simulating: template root added as logical child BEFORE parent is set
- ((IControlTemplated)contentView1).AddLogicalChild(border1);
- ((IControlTemplated)contentView2).AddLogicalChild(border2);
-
- // Now add ContentViews to layout (parent set AFTER template already applied)
- layout.Add(contentView1);
- layout.Add(contentView2);
-
- // Initially, neither button should be checked (no IsChecked="True" was set)
- Assert.False(radioButton1.IsChecked);
- Assert.False(radioButton2.IsChecked);
- Assert.Null(layout.GetValue(RadioButtonGroup.SelectedValueProperty));
-
- // Check radio button 1 - only rb1 should be checked and SelectedValue updated
- radioButton1.IsChecked = true;
- Assert.True(radioButton1.IsChecked);
- Assert.False(radioButton2.IsChecked);
- Assert.Equal("opt1", layout.GetValue(RadioButtonGroup.SelectedValueProperty));
-
- // Check radio button 2 - radio button 1 should be unchecked and SelectedValue updated
- radioButton2.IsChecked = true;
- Assert.False(radioButton1.IsChecked);
- Assert.True(radioButton2.IsChecked);
- Assert.Equal("opt2", layout.GetValue(RadioButtonGroup.SelectedValueProperty));
- }
-
- [Fact]
- public void RadioButtonGroupAutoChecksMatchingButtonInContentViewWhenSelectedValuePreset()
- {
- // Verifies the positive auto-check path for the ContentView/ControlTemplate scenario
- // when SelectedValue IS explicitly set on the group, a RadioButton
- // added through a ContentView ControlTemplate with a matching Value must be auto-checked.
- var groupName = "Test2";
- var layout = new VerticalStackLayout();
- layout.SetValue(RadioButtonGroup.GroupNameProperty, groupName);
-
- // Pre-set SelectedValue BEFORE adding buttons (simulates binding from ViewModel)
- layout.SetValue(RadioButtonGroup.SelectedValueProperty, "opt2");
-
- var radioButton1 = new RadioButton { Content = "Option 1", Value = "opt1", GroupName = groupName };
- var radioButton2 = new RadioButton { Content = "Option 2", Value = "opt2", GroupName = groupName };
-
- var border1 = new Border { Content = radioButton1 };
- var border2 = new Border { Content = radioButton2 };
-
- var contentView1 = new ContentView();
- var contentView2 = new ContentView();
-
- // Apply ControlTemplate before adding to layout
- ((IControlTemplated)contentView1).AddLogicalChild(border1);
- ((IControlTemplated)contentView2).AddLogicalChild(border2);
-
- layout.Add(contentView1);
- layout.Add(contentView2);
-
- // RadioButton whose Value matches the pre-set SelectedValue must be auto-checked
- Assert.False(radioButton1.IsChecked);
- Assert.True(radioButton2.IsChecked);
- Assert.Equal("opt2", layout.GetValue(RadioButtonGroup.SelectedValueProperty));
- }
}
}
diff --git a/src/Controls/tests/DeviceTests/Elements/CollectionView/CollectionViewTests.iOS.cs b/src/Controls/tests/DeviceTests/Elements/CollectionView/CollectionViewTests.iOS.cs
index 398744a3bffe..0691177c367e 100644
--- a/src/Controls/tests/DeviceTests/Elements/CollectionView/CollectionViewTests.iOS.cs
+++ b/src/Controls/tests/DeviceTests/Elements/CollectionView/CollectionViewTests.iOS.cs
@@ -310,36 +310,6 @@ public object LoadDataTemplate()
}
}
- [Fact]
- public async Task CollectionViewScrollsToTopIsEnabled()
- {
- EnsureHandlerCreated(builder =>
- {
- builder.ConfigureMauiHandlers(handlers =>
- {
- handlers.AddHandler();
- handlers.AddHandler();
- });
- });
-
- var collectionView = new CollectionView
- {
- ItemsSource = Enumerable.Range(0, 20).Select(i => $"Item {i}").ToList(),
- ItemTemplate = new DataTemplate(() =>
- {
- var label = new Label();
- label.SetBinding(Label.TextProperty, ".");
- return label;
- })
- };
-
- await CreateHandlerAndAddToWindow(collectionView, handler =>
- {
- var uiCollectionView = handler.Controller.CollectionView;
- Assert.True(uiCollectionView.ScrollsToTop, "CollectionView's UICollectionView should have ScrollsToTop enabled");
- });
- }
-
Rect GetCollectionViewCellBounds(IView cellContent)
{
if (!cellContent.ToPlatform().IsLoaded())
diff --git a/src/Controls/tests/DeviceTests/Elements/ContentView/ContentViewTests.Windows.cs b/src/Controls/tests/DeviceTests/Elements/ContentView/ContentViewTests.Windows.cs
index 61f777a5432e..2e32a119dae1 100644
--- a/src/Controls/tests/DeviceTests/Elements/ContentView/ContentViewTests.Windows.cs
+++ b/src/Controls/tests/DeviceTests/Elements/ContentView/ContentViewTests.Windows.cs
@@ -1,10 +1,5 @@
-using System.Threading.Tasks;
-using Microsoft.Maui.Controls;
-using Microsoft.Maui.Handlers;
+using Microsoft.Maui.Handlers;
using Microsoft.Maui.Platform;
-using Microsoft.UI.Xaml.Automation;
-using Microsoft.UI.Xaml.Automation.Peers;
-using Xunit;
namespace Microsoft.Maui.DeviceTests
{
@@ -22,76 +17,5 @@ static int GetContentChildCount(ContentViewHandler contentViewHandler)
else
return 0;
}
-
- static AutomationPeer GetOrCreateAutomationPeer(ContentPanel contentPanel)
- => new ContentPanel.ContentPanelAutomationPeer(contentPanel);
-
- [Fact(DisplayName = "ContentView With Description Prevents Duplicate Narrator Announcements")]
- public async Task ContentViewWithDescriptionHidesChildrenFromNarrator()
- {
- SetupBuilder();
-
- var label = new Label { Text = "Child Label Text" };
- var contentView = new ContentView { Content = label };
- SemanticProperties.SetDescription(contentView, "ContentView Description");
-
- await CreateHandlerAndAddToWindow(contentView, async (handler) =>
- {
- var contentPanel = handler.PlatformView as ContentPanel;
- Assert.NotNull(contentPanel);
-
- // Call UpdateSemantics manually because handler.UpdateValue uses handler.VirtualView
- // which doesn't have Semantics populated in the test context
- var view = contentView as IView;
- contentPanel.UpdateSemantics(view);
-
- var peer = GetOrCreateAutomationPeer(contentPanel);
- Assert.NotNull(peer);
-
- var name = Microsoft.UI.Xaml.Automation.AutomationProperties.GetName(contentPanel);
- Assert.Equal("ContentView Description", name);
-
- // ControlType should be Text (not Group) to prevent Narrator from saying "group"
- var controlType = peer.GetAutomationControlType();
- Assert.Equal(AutomationControlType.Text, controlType);
-
- // Children should be hidden to prevent duplicate announcements
- var children = peer.GetChildren();
- Assert.Null(children);
-
- // LocalizedControlType should be empty to prevent suffix
- var localizedControlType = peer.GetLocalizedControlType();
- Assert.Equal(string.Empty, localizedControlType);
-
- await Task.CompletedTask;
- });
- }
-
- [Fact(DisplayName = "ContentView Without Description Shows Children Normally")]
- public async Task ContentViewWithoutDescriptionShowsChildren()
- {
- SetupBuilder();
-
- var label = new Label { Text = "Child Label Text" };
- var contentView = new ContentView { Content = label };
-
- await CreateHandlerAndAddToWindow(contentView, async (handler) =>
- {
- var contentPanel = handler.PlatformView as ContentPanel;
- Assert.NotNull(contentPanel);
-
- var peer = GetOrCreateAutomationPeer(contentPanel);
- Assert.NotNull(peer);
-
- var controlType = peer.GetAutomationControlType();
- Assert.Equal(AutomationControlType.Custom, controlType);
-
- var children = peer.GetChildren();
- Assert.NotNull(children);
- Assert.NotEmpty(children);
-
- await Task.CompletedTask;
- });
- }
}
}
diff --git a/src/Controls/tests/DeviceTests/Elements/Entry/EntryTests.Windows.cs b/src/Controls/tests/DeviceTests/Elements/Entry/EntryTests.Windows.cs
index 61118bec0daf..d86cb99da135 100644
--- a/src/Controls/tests/DeviceTests/Elements/Entry/EntryTests.Windows.cs
+++ b/src/Controls/tests/DeviceTests/Elements/Entry/EntryTests.Windows.cs
@@ -112,31 +112,5 @@ await InvokeOnMainThreadAsync(() =>
Assert.Equal(new string('●', entry.Text.Length), passwordTextBox.Text);
});
}
-
- [Fact]
- [Description("Password entry should not crash when platform text is set from empty")]
- public async Task PasswordEntryPlatformSetDoesNotCrash()
- {
- var entry = new Entry
- {
- Text = string.Empty,
- IsPassword = true
- };
-
- var handler = await CreateHandlerAsync(entry);
-
- await InvokeOnMainThreadAsync(() =>
- {
- var platformControl = GetPlatformControl(handler);
- var passwordTextBox = platformControl as Microsoft.Maui.Platform.MauiPasswordTextBox;
-
- Assert.NotNull(passwordTextBox);
- Assert.True(passwordTextBox.IsPassword);
-
- // Setting Text on an empty password entry triggers TextChanging event which previously threw ArgumentOutOfRangeException
- passwordTextBox.Text = "test";
- Assert.Equal("test", passwordTextBox.Text);
- });
- }
}
}
diff --git a/src/Controls/tests/DeviceTests/Elements/HybridWebView/HybridWebViewTestsBase.cs b/src/Controls/tests/DeviceTests/Elements/HybridWebView/HybridWebViewTestsBase.cs
index 68522216d53e..f5c3e3609b37 100644
--- a/src/Controls/tests/DeviceTests/Elements/HybridWebView/HybridWebViewTestsBase.cs
+++ b/src/Controls/tests/DeviceTests/Elements/HybridWebView/HybridWebViewTestsBase.cs
@@ -40,7 +40,6 @@ protected async Task RunTest(string? defaultFile, Func test
HybridRoot = "HybridTestRoot",
DefaultFile = defaultFile ?? "index.html",
};
-
await RunTest(hybridWebView, (handler, view) => test(view));
}
@@ -59,12 +58,7 @@ await AttachAndRun(hybridWebView, async handler =>
{
await WebViewHelpers.WaitForHybridWebViewLoaded(hybridWebView);
- // Use a cancellation token with a timeout
- using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(15));
-
- var testWrapper = test((HybridWebViewHandler)handler, hybridWebView);
-
- await testWrapper.WaitAsync(cts.Token);
+ await test((HybridWebViewHandler)handler, hybridWebView);
});
}
diff --git a/src/Controls/tests/DeviceTests/Elements/HybridWebView/HybridWebViewTests_EvaluateJavaScriptAsync.cs b/src/Controls/tests/DeviceTests/Elements/HybridWebView/HybridWebViewTests_EvaluateJavaScriptAsync.cs
index 9b6332be89e6..fcd6b52346cf 100644
--- a/src/Controls/tests/DeviceTests/Elements/HybridWebView/HybridWebViewTests_EvaluateJavaScriptAsync.cs
+++ b/src/Controls/tests/DeviceTests/Elements/HybridWebView/HybridWebViewTests_EvaluateJavaScriptAsync.cs
@@ -11,56 +11,15 @@ namespace Microsoft.Maui.DeviceTests;
public partial class HybridWebViewTests_EvaluateJavaScriptAsync : HybridWebViewTestsBase
{
[Fact]
- public Task EvaluateJavaScriptAsync_WithStringParameters() =>
+ public Task EvaluateJavaScriptAndGetResult() =>
RunTest(async (hybridWebView) =>
{
// Run some JavaScript to call a method and get result
var result1 = await hybridWebView.EvaluateJavaScriptAsync("EvaluateMeWithParamsAndReturn('abc', 'def')");
Assert.Equal("abcdef", result1);
- });
-
- [Fact]
- public Task EvaluateJavaScriptAsync_WithNumberParameters() =>
- RunTest(async (hybridWebView) =>
- {
- // Run some JavaScript to call a method and get result
- var result1 = await hybridWebView.EvaluateJavaScriptAsync("EvaluateMeWithParamsAndReturn(1, 2)");
- Assert.Equal("3", result1);
- });
- [Fact]
- public Task EvaluateJavaScriptAsync_GetsProperty() =>
- RunTest(async (hybridWebView) =>
- {
// Run some JavaScript to get an arbitrary result by running JavaScript
var result2 = await hybridWebView.EvaluateJavaScriptAsync("window.TestKey");
Assert.Equal("test_value", result2);
});
-
- [Fact]
- public Task EvaluateJavaScriptAsync_HandlesDoubleQuotes() =>
- RunTest(async (hybridWebView) =>
- {
- // Run some JavaScript to call a method and get result
- var result1 = await hybridWebView.EvaluateJavaScriptAsync("EvaluateMeWithParamsAndReturn('\"Hel', 'lo!\"')");
- Assert.Equal("\"Hello!\"", result1);
- });
-
- [Fact]
- public Task EvaluateJavaScriptAsync_HandlesSingleQuotes() =>
- RunTest(async (hybridWebView) =>
- {
- // Run some JavaScript to call a method and get result
- var result1 = await hybridWebView.EvaluateJavaScriptAsync("EvaluateMeWithParamsAndReturn('\\'Hel', 'lo!\\'')");
- Assert.Equal("'Hello!'", result1);
- });
-
- [Fact]
- public Task EvaluateJavaScriptAsync_HandlesDoubleAndSingleQuotes() =>
- RunTest(async (hybridWebView) =>
- {
- // Run some JavaScript to call a method and get result
- var result1 = await hybridWebView.EvaluateJavaScriptAsync("EvaluateMeWithParamsAndReturn('\"Hel', 'lo!\\'')");
- Assert.Equal("\"Hello!'", result1);
- });
}
diff --git a/src/Controls/tests/DeviceTests/Elements/HybridWebView/HybridWebViewTests_InvokeJavaScriptAsync.cs b/src/Controls/tests/DeviceTests/Elements/HybridWebView/HybridWebViewTests_InvokeJavaScriptAsync.cs
index 95fe209dd847..1d0b36a7faad 100644
--- a/src/Controls/tests/DeviceTests/Elements/HybridWebView/HybridWebViewTests_InvokeJavaScriptAsync.cs
+++ b/src/Controls/tests/DeviceTests/Elements/HybridWebView/HybridWebViewTests_InvokeJavaScriptAsync.cs
@@ -1,8 +1,6 @@
#nullable enable
using System;
using System.Collections.Generic;
-using System.Text;
-using System.Text.Json;
using System.Text.Json.Serialization;
using System.Threading.Tasks;
using Xunit;
@@ -31,7 +29,7 @@ public Task RequestFileFromJS(string url, int expectedStatus) =>
});
[Fact]
- public Task InvokeJavaScript_WithParametersAndNulls_AndComplexResult() =>
+ public Task InvokeJavaScriptMethodWithParametersAndNullsAndComplexResult() =>
RunTest(async (hybridWebView) =>
{
var x = 123.456m;
@@ -49,7 +47,7 @@ public Task InvokeJavaScript_WithParametersAndNulls_AndComplexResult() =>
});
[Fact]
- public Task InvokeJavaScript_WithParameters_AndDecimalResult() =>
+ public Task InvokeJavaScriptMethodWithParametersAndDecimalResult() =>
RunTest(async (hybridWebView) =>
{
var x = 123.456m;
@@ -68,7 +66,7 @@ public Task InvokeJavaScript_WithParameters_AndDecimalResult() =>
[InlineData(-123.456)]
[InlineData(0.0)]
[InlineData(123.456)]
- public Task InvokeJavaScript_WithParameters_AndDoubleResult(double expected) =>
+ public Task InvokeJavaScriptMethodWithParametersAndDoubleResult(double expected) =>
RunTest(async (hybridWebView) =>
{
var result = await hybridWebView.InvokeJavaScriptAsync(
@@ -85,7 +83,7 @@ public Task InvokeJavaScript_WithParameters_AndDoubleResult(double expected) =>
[InlineData(-123.456)]
[InlineData(0.0)]
[InlineData(123.456)]
- public Task InvokeJavaScript_WithParameters_AndNullableDoubleResult(double? expected) =>
+ public Task InvokeJavaScriptMethodWithParametersAndNullableDoubleResult(double? expected) =>
RunTest(async (hybridWebView) =>
{
var result = await hybridWebView.InvokeJavaScriptAsync(
@@ -98,7 +96,7 @@ public Task InvokeJavaScript_WithParameters_AndNullableDoubleResult(double? expe
});
[Fact]
- public Task InvokeJavaScript_WithParameters_AndNewDoubleResult() =>
+ public Task InvokeJavaScriptMethodWithParametersAndNewDoubleResult() =>
RunTest(async (hybridWebView) =>
{
var x = 123.456m;
@@ -117,7 +115,7 @@ public Task InvokeJavaScript_WithParameters_AndNewDoubleResult() =>
[InlineData(-123)]
[InlineData(0)]
[InlineData(123)]
- public Task InvokeJavaScript_WithParameters_AndIntResult(int expected) =>
+ public Task InvokeJavaScriptMethodWithParametersAndIntResult(int expected) =>
RunTest(async (hybridWebView) =>
{
var result = await hybridWebView.InvokeJavaScriptAsync(
@@ -134,7 +132,7 @@ public Task InvokeJavaScript_WithParameters_AndIntResult(int expected) =>
[InlineData(-123)]
[InlineData(0)]
[InlineData(123)]
- public Task InvokeJavaScript_WithParameters_AndNullableIntResult(int? expected) =>
+ public Task InvokeJavaScriptMethodWithParametersAndNullableIntResult(int? expected) =>
RunTest(async (hybridWebView) =>
{
var result = await hybridWebView.InvokeJavaScriptAsync(
@@ -147,7 +145,7 @@ public Task InvokeJavaScript_WithParameters_AndNullableIntResult(int? expected)
});
[Fact]
- public Task InvokeJavaScript_WithParameters_AndNewIntResult() =>
+ public Task InvokeJavaScriptMethodWithParametersAndNewIntResult() =>
RunTest(async (hybridWebView) =>
{
var x = 123;
@@ -168,7 +166,7 @@ public Task InvokeJavaScript_WithParameters_AndNewIntResult() =>
[InlineData("foo")]
[InlineData("null")]
[InlineData("undefined")]
- public Task InvokeJavaScript_WithParameters_AndStringResult(string? expected) =>
+ public Task InvokeJavaScriptMethodWithParametersAndStringResult(string? expected) =>
RunTest(async (hybridWebView) =>
{
var result = await hybridWebView.InvokeJavaScriptAsync(
@@ -181,7 +179,7 @@ public Task InvokeJavaScript_WithParameters_AndStringResult(string? expected) =>
});
[Fact]
- public Task InvokeJavaScript_WithParameters_AndNewStringResult() =>
+ public Task InvokeJavaScriptMethodWithParametersAndNewStringResult() =>
RunTest(async (hybridWebView) =>
{
var x = "abc";
@@ -199,7 +197,7 @@ public Task InvokeJavaScript_WithParameters_AndNewStringResult() =>
[Theory]
[InlineData(true)]
[InlineData(false)]
- public Task InvokeJavaScript_WithParameters_AndBoolResult(bool expected) =>
+ public Task InvokeJavaScriptMethodWithParametersAndBoolResult(bool expected) =>
RunTest(async (hybridWebView) =>
{
var result = await hybridWebView.InvokeJavaScriptAsync(
@@ -212,7 +210,7 @@ public Task InvokeJavaScript_WithParameters_AndBoolResult(bool expected) =>
});
[Fact]
- public Task InvokeJavaScript_WithParameters_AndComplexResult() =>
+ public Task InvokeJavaScriptMethodWithParametersAndComplexResult() =>
RunTest(async (hybridWebView) =>
{
var x = 123.456m;
@@ -230,7 +228,7 @@ public Task InvokeJavaScript_WithParameters_AndComplexResult() =>
});
[Fact]
- public Task InvokeJavaScript_WithParameters_AndAsyncComplexResult() =>
+ public Task InvokeAsyncJavaScriptMethodWithParametersAndComplexResult() =>
RunTest(async (hybridWebView) =>
{
var s1 = "new_key";
@@ -250,7 +248,7 @@ public Task InvokeJavaScript_WithParameters_AndAsyncComplexResult() =>
});
[Fact]
- public Task InvokeJavaScript_WithParameters_AndVoidReturn() =>
+ public Task InvokeJavaScriptMethodWithParametersAndVoidReturn() =>
RunTest(async (hybridWebView) =>
{
var x = 123.456m;
@@ -269,7 +267,7 @@ await hybridWebView.InvokeJavaScriptAsync(
});
[Fact]
- public Task InvokeJavaScript_WithParameters_AndVoidReturn_UsingObjectReturnMethod() =>
+ public Task InvokeJavaScriptMethodWithParametersAndVoidReturnUsingObjectReturnMethod() =>
RunTest(async (hybridWebView) =>
{
var x = 123.456m;
@@ -291,7 +289,7 @@ public Task InvokeJavaScript_WithParameters_AndVoidReturn_UsingObjectReturnMetho
});
[Fact]
- public Task InvokeJavaScript_WithParameters_AndVoidReturn_UsingNullReturnMethod() =>
+ public Task InvokeJavaScriptMethodWithParametersAndVoidReturnUsingNullReturnMethod() =>
RunTest(async (hybridWebView) =>
{
var x = 123.456m;
@@ -315,10 +313,10 @@ public Task InvokeJavaScript_WithParameters_AndVoidReturn_UsingNullReturnMethod(
[Theory]
[InlineData("")]
[InlineData("Async")]
- public Task InvokeJavaScript_ThatThrowsNumber(string type) =>
+ public Task InvokeJavaScriptMethodThatThrowsNumber(string type) =>
RunExceptionTest("EvaluateMeWithParamsThatThrows" + type, 1, ex =>
{
- Assert.Equal("InvokeJavaScriptAsync threw an exception: 777.777", ex.Message);
+ Assert.Equal("InvokeJavaScript threw an exception: 777.777", ex.Message);
Assert.Equal("777.777", ex.InnerException?.Message);
Assert.Null(ex.InnerException?.Data["JavaScriptErrorName"]);
Assert.NotNull(ex.InnerException?.StackTrace);
@@ -327,10 +325,10 @@ public Task InvokeJavaScript_ThatThrowsNumber(string type) =>
[Theory]
[InlineData("")]
[InlineData("Async")]
- public Task InvokeJavaScript_ThatThrowsString(string type) =>
+ public Task InvokeJavaScriptMethodThatThrowsString(string type) =>
RunExceptionTest("EvaluateMeWithParamsThatThrows" + type, 2, ex =>
{
- Assert.Equal("InvokeJavaScriptAsync threw an exception: String: 777.777", ex.Message);
+ Assert.Equal("InvokeJavaScript threw an exception: String: 777.777", ex.Message);
Assert.Equal("String: 777.777", ex.InnerException?.Message);
Assert.Null(ex.InnerException?.Data["JavaScriptErrorName"]);
Assert.NotNull(ex.InnerException?.StackTrace);
@@ -339,10 +337,10 @@ public Task InvokeJavaScript_ThatThrowsString(string type) =>
[Theory]
[InlineData("")]
[InlineData("Async")]
- public Task InvokeJavaScript_ThatThrowsError(string type) =>
+ public Task InvokeJavaScriptMethodThatThrowsError(string type) =>
RunExceptionTest("EvaluateMeWithParamsThatThrows" + type, 3, ex =>
{
- Assert.Equal("InvokeJavaScriptAsync threw an exception: Generic Error: 777.777", ex.Message);
+ Assert.Equal("InvokeJavaScript threw an exception: Generic Error: 777.777", ex.Message);
Assert.Equal("Generic Error: 777.777", ex.InnerException?.Message);
Assert.Equal("Error", ex.InnerException?.Data["JavaScriptErrorName"]);
Assert.NotNull(ex.InnerException?.StackTrace);
@@ -351,7 +349,7 @@ public Task InvokeJavaScript_ThatThrowsError(string type) =>
[Theory]
[InlineData("")]
[InlineData("Async")]
- public Task InvokeJavaScript_ThatThrowsTypedNumber(string type) =>
+ public Task InvokeJavaScriptMethodThatThrowsTypedNumber(string type) =>
RunExceptionTest("EvaluateMeWithParamsThatThrows" + type, 4, ex =>
{
Assert.Contains("undefined", ex.Message, StringComparison.OrdinalIgnoreCase);
@@ -360,163 +358,6 @@ public Task InvokeJavaScript_ThatThrowsTypedNumber(string type) =>
Assert.NotNull(ex.InnerException?.StackTrace);
});
- [Fact]
- public Task InvokeJavaScript_WithJsonStringArgument() =>
- RunTest(async (hybridWebView) =>
- {
- // Create a dictionary that will be serialized to JSON
- var contextArg = new Dictionary
- {
- { "userId", "userIdValue" },
- { "sessionId", "session123" },
- { "timestamp", "2025-11-11T01:30:00Z" }
- };
-
- // Serialize to JSON string (without base64 encoding)
- string contextArgString = JsonSerializer.Serialize(contextArg);
-
- // This should not timeout - the JSON string should be handled correctly
- var result = await hybridWebView.InvokeJavaScriptAsync(
- "EchoJsonParameter",
- InvokeJsonContext.Default.String,
- [contextArgString],
- [InvokeJsonContext.Default.String]);
-
- // Verify the result matches the input
- Assert.Equal(contextArgString, result);
- });
-
- [Fact]
- public Task InvokeJavaScript_WithDictionaryArgument() =>
- RunTest(async (hybridWebView) =>
- {
- // Create a dictionary that will be serialized to JSON
- var contextArg = new Dictionary
- {
- { "userId", "userIdValue" },
- { "sessionId", "session123" },
- { "timestamp", "2025-11-11T01:30:00Z" }
- };
-
- // This should not timeout - the JSON string should be handled correctly
- var result = await hybridWebView.InvokeJavaScriptAsync(
- "EchoJsonStringifyParameter",
- InvokeJsonContext.Default.String,
- [contextArg],
- [InvokeJsonContext.Default.DictionaryStringString]);
-
- // Serialize to JSON string (without base64 encoding)
- string contextArgString = JsonSerializer.Serialize(contextArg);
-
- // Verify the result matches the input
- Assert.Equal(contextArgString, result);
- });
-
- [Fact]
- public Task InvokeJavaScript_WithComplexJsonString() =>
- RunTest(async (hybridWebView) =>
- {
- // Create a more complex JSON with special characters that might cause escaping issues
- var complexObject = new Dictionary
- {
- { "string", "value with \"quotes\" and 'apostrophes'" },
- { "number", 123.456 },
- { "boolean", true },
- { "nested", new Dictionary
- {
- { "key1", "value1" },
- { "key2", "value2" }
- }
- }
- };
-
- string jsonString = JsonSerializer.Serialize(complexObject);
-
- var result = await hybridWebView.InvokeJavaScriptAsync(
- "ParseAndStringifyJson",
- InvokeJsonContext.Default.String,
- [jsonString],
- [InvokeJsonContext.Default.String]);
-
- // The JavaScript function should parse and re-stringify the JSON
- // The result should be equivalent (though formatting might differ)
- Assert.NotNull(result);
- Assert.Contains("quotes", result, StringComparison.Ordinal);
- Assert.Contains("apostrophes", result, StringComparison.Ordinal);
- });
-
- [Fact]
- public Task InvokeJavaScript_WithMultipleJsonStringArguments() =>
- RunTest(async (hybridWebView) =>
- {
- var firstJson = JsonSerializer.Serialize(new { type = "user", id = 1 });
- var secondJson = JsonSerializer.Serialize(new { type = "session", id = 2 });
-
- var result = await hybridWebView.InvokeJavaScriptAsync(
- "ConcatenateJsonStrings",
- InvokeJsonContext.Default.String,
- [firstJson, secondJson],
- [InvokeJsonContext.Default.String, InvokeJsonContext.Default.String]);
-
- Assert.NotNull(result);
- Assert.Contains("user", result, StringComparison.Ordinal);
- Assert.Contains("session", result, StringComparison.Ordinal);
- });
-
- [Fact]
- public Task InvokeJavaScript_WithBase64EncodedJsonString() =>
- RunTest(async (hybridWebView) =>
- {
- var contextArg = new Dictionary
- {
- { "userId", "userIdValue" }
- };
-
- string contextArgString = JsonSerializer.Serialize(contextArg);
-
- // Base64 encode (the workaround from the issue)
- string base64String = Convert.ToBase64String(Encoding.UTF8.GetBytes(contextArgString));
-
- var result = await hybridWebView.InvokeJavaScriptAsync(
- "DecodeBase64AndEcho",
- InvokeJsonContext.Default.String,
- [base64String],
- [InvokeJsonContext.Default.String]);
-
- // The JavaScript function should decode and return the original JSON
- Assert.Equal(contextArgString, result);
- });
-
- [Fact]
- public Task InvokeJavaScript_WithJsonArrayArgument() =>
- RunTest(async (hybridWebView) =>
- {
- var jsonArray = JsonSerializer.Serialize(new[] { "item1", "item2", "item3" });
-
- var result = await hybridWebView.InvokeJavaScriptAsync(
- "CountJsonArrayItems",
- InvokeJsonContext.Default.Int32,
- [jsonArray],
- [InvokeJsonContext.Default.String]);
-
- Assert.Equal(3, result);
- });
-
- [Fact]
- public Task InvokeJavaScript_WithEmptyJsonObject() =>
- RunTest(async (hybridWebView) =>
- {
- var emptyJson = JsonSerializer.Serialize(new Dictionary());
-
- var result = await hybridWebView.InvokeJavaScriptAsync(
- "EchoJsonParameter",
- InvokeJsonContext.Default.String,
- [emptyJson],
- [InvokeJsonContext.Default.String]);
-
- Assert.Equal("{}", result);
- });
-
Task RunExceptionTest(string method, int errorType, Action test) =>
RunTest(async (hybridWebView) =>
{
diff --git a/src/Controls/tests/DeviceTests/Elements/HybridWebView/HybridWebViewTests_SetInvokeJavaScriptTarget.cs b/src/Controls/tests/DeviceTests/Elements/HybridWebView/HybridWebViewTests_SetInvokeJavaScriptTarget.cs
index 2a9439ed743f..a904e3ccf467 100644
--- a/src/Controls/tests/DeviceTests/Elements/HybridWebView/HybridWebViewTests_SetInvokeJavaScriptTarget.cs
+++ b/src/Controls/tests/DeviceTests/Elements/HybridWebView/HybridWebViewTests_SetInvokeJavaScriptTarget.cs
@@ -139,8 +139,8 @@ private class InvokeJavaScriptAsyncTestData : IEnumerable
{
public IEnumerator GetEnumerator()
{
- const string ComplexResult = "{\"result\":123,\"operationName\":\"Test\"}";
- const string DictionaryResult = "{\"first\":111,\"second\":222,\"third\":333}";
+ const string ComplexResult = "{\\\"result\\\":123,\\\"operationName\\\":\\\"Test\\\"}";
+ const string DictionaryResult = "{\\\"first\\\":111,\\\"second\\\":222,\\\"third\\\":333}";
const int ValueTypeResult = 2;
// Test variations of:
diff --git a/src/Controls/tests/DeviceTests/Elements/Label/LabelTests.iOS.cs b/src/Controls/tests/DeviceTests/Elements/Label/LabelTests.iOS.cs
index 05fb39f5a88b..14fa067a44e2 100644
--- a/src/Controls/tests/DeviceTests/Elements/Label/LabelTests.iOS.cs
+++ b/src/Controls/tests/DeviceTests/Elements/Label/LabelTests.iOS.cs
@@ -126,7 +126,7 @@ public static IEnumerable GetCharacterSpacingWithLineHeightWithTextDec
new object[] { label1, 5d, 1.5d, TextDecorations.Underline },
new object[] { label2, 5d, 1.5d, TextDecorations.Strikethrough },
new object[] { label3, 0d, 0d, TextDecorations.None },
- new object[] { label4, 5d, 1.5d, TextDecorations.Underline }
+ new object[] { label4, 0d, 0d, TextDecorations.None }
};
}
diff --git a/src/Controls/tests/DeviceTests/Elements/Shell/ShellFlyoutTests.cs b/src/Controls/tests/DeviceTests/Elements/Shell/ShellFlyoutTests.cs
index 76180c67934b..8113f4fec565 100644
--- a/src/Controls/tests/DeviceTests/Elements/Shell/ShellFlyoutTests.cs
+++ b/src/Controls/tests/DeviceTests/Elements/Shell/ShellFlyoutTests.cs
@@ -323,20 +323,14 @@ await RunShellTest(shell =>
}
else
{
- // After scrolling, the header height may include the safe area margin
- // depending on the content type and how InvalidateMeasure is triggered.
- var safeAreaTop = GetSafeArea(handler.ToPlatform()).Top;
- Assert.True(
- scrolledBox.Height >= headerRequestedHeight - 0.3 &&
- scrolledBox.Height <= headerRequestedHeight + safeAreaTop + 0.3,
- $"Header Height: expected between {headerRequestedHeight} and {headerRequestedHeight + safeAreaTop}, actual: {scrolledBox.Height}");
+ AssertionExtensions.CloseEnough(headerRequestedHeight, scrolledBox.Height, 0.3, "Header Height");
if (flyoutHeaderBehavior == FlyoutHeaderBehavior.Scroll)
{
- // scrolledBox.Y is negative because the header is scrolled up
- var diff = scrolledBox.Y + scrolledBox.Height;
+ // scrolledBoy.Y is negative because the header is scrolled up
+ var diff = scrolledBox.Y + headerRequestedHeight;
var epsilon = 0.3;
- Assert.True(diff <= epsilon, $"Scrolled Header: position {scrolledBox.Y} is not enough to cover height ({scrolledBox.Height}). Epsilon: {epsilon}");
+ Assert.True(diff <= epsilon, $"Scrolled Header: position {scrolledBox.Y} is no enough to cover height ({scrolledBox.Height * -1}). Epsilon: {epsilon}");
}
else
{
diff --git a/src/Controls/tests/DeviceTests/Elements/Shell/ShellTests.iOS.cs b/src/Controls/tests/DeviceTests/Elements/Shell/ShellTests.iOS.cs
index e40cafcbc6ba..a7b8fb032e3d 100644
--- a/src/Controls/tests/DeviceTests/Elements/Shell/ShellTests.iOS.cs
+++ b/src/Controls/tests/DeviceTests/Elements/Shell/ShellTests.iOS.cs
@@ -619,34 +619,6 @@ async Task TapToSelect(ContentPage page)
await OnNavigatedToAsync(page);
}
- [Fact(DisplayName = "Shell Flyout Table View Has ScrollsToTop Disabled")]
- public async Task ShellFlyoutTableViewScrollsToTopIsDisabled()
- {
- SetupBuilder();
- var shell = await CreateShellAsync((shell) =>
- {
- shell.Items.Add(new ContentPage() { Content = new Label() { Text = "Test Page" } });
- });
-
- await CreateHandlerAndAddToWindow(shell, (handler) =>
- {
- var flyoutContent = handler.ViewController
- .ChildViewControllers
- .OfType()
- .First();
-
- var tableViewController = flyoutContent.ChildViewControllers
- .OfType()
- .FirstOrDefault();
-
- Assert.NotNull(tableViewController);
- Assert.False(tableViewController.TableView.ScrollsToTop,
- "Shell flyout's table view should have ScrollsToTop disabled to avoid conflicting with content scroll views");
-
- return Task.CompletedTask;
- });
- }
-
class ModalShellPage : ContentPage
{
public ModalShellPage()
diff --git a/src/Controls/tests/DeviceTests/Resources/Raw/HybridTestRoot/index.html b/src/Controls/tests/DeviceTests/Resources/Raw/HybridTestRoot/index.html
index 49709cfa07da..bd5ee137d8d4 100644
--- a/src/Controls/tests/DeviceTests/Resources/Raw/HybridTestRoot/index.html
+++ b/src/Controls/tests/DeviceTests/Resources/Raw/HybridTestRoot/index.html
@@ -158,63 +158,6 @@
// test evaluate arbitrary javascript
window.TestKey = 'test_value';
- // Test functions for JSON string arguments (issue 32438)
-
- // Echo back the JSON parameter as-is
- function EchoJsonParameter(jsonString) {
- return jsonString;
- }
-
- // Echo back the parameter as a JSON string
- function EchoJsonStringifyParameter(jsonString) {
- return JSON.stringify(jsonString);
- }
-
-
- // Parse JSON string and stringify it back
- function ParseAndStringifyJson(jsonString) {
- try {
- const parsed = JSON.parse(jsonString);
- return JSON.stringify(parsed);
- } catch (e) {
- throw new Error(`Failed to parse JSON: ${e.message}`);
- }
- }
-
- // Concatenate two JSON strings into an array
- function ConcatenateJsonStrings(json1, json2) {
- try {
- const obj1 = JSON.parse(json1);
- const obj2 = JSON.parse(json2);
- return JSON.stringify([obj1, obj2]);
- } catch (e) {
- throw new Error(`Failed to concatenate JSON strings: ${e.message}`);
- }
- }
-
- // Decode base64 string and echo back the decoded JSON
- function DecodeBase64AndEcho(base64String) {
- try {
- const decoded = atob(base64String);
- return decoded;
- } catch (e) {
- throw new Error(`Failed to decode base64: ${e.message}`);
- }
- }
-
- // Count items in a JSON array
- function CountJsonArrayItems(jsonArrayString) {
- try {
- const array = JSON.parse(jsonArrayString);
- if (!Array.isArray(array)) {
- throw new Error('Argument is not a JSON array');
- }
- return array.length;
- } catch (e) {
- throw new Error(`Failed to count array items: ${e.message}`);
- }
- }
-
diff --git a/src/Controls/tests/SourceGen.UnitTests/XCodeTests.cs b/src/Controls/tests/SourceGen.UnitTests/XCodeTests.cs
deleted file mode 100644
index ac1bff38c4b3..000000000000
--- a/src/Controls/tests/SourceGen.UnitTests/XCodeTests.cs
+++ /dev/null
@@ -1,374 +0,0 @@
-using System;
-using System.Linq;
-using Microsoft.CodeAnalysis;
-using Microsoft.Maui.Controls.Xaml.UnitTests.SourceGen;
-using Xunit;
-
-using static Microsoft.Maui.Controls.Xaml.UnitTests.SourceGen.SourceGeneratorDriver;
-
-namespace Microsoft.Maui.Controls.SourceGen.UnitTests;
-
-public class XCodeTests : SourceGenXamlInitializeComponentTestBase
-{
- string? GetXCodeOutput(GeneratorDriverRunResult result)
- => result.Results.SingleOrDefault().GeneratedSources
- .SingleOrDefault(gs => gs.HintName.EndsWith(".xcode.cs"))
- .SourceText?.ToString();
-
- [Fact]
- public void XCode_GeneratesPartialClassWithMethod()
- {
- var xaml =
-"""
-
-
- "Hello from x:Code!";
- ]]>
-
-
-""";
-
- var codeBehind =
-"""
-using Microsoft.Maui.Controls;
-using Microsoft.Maui.Controls.Xaml;
-
-namespace TestApp;
-
-[XamlProcessing(XamlInflator.SourceGen)]
-public partial class XCodePage : ContentPage
-{
- public XCodePage() => InitializeComponent();
-}
-""";
-
- var (result, _) = RunGenerator(xaml, codeBehind);
- var xcode = GetXCodeOutput(result);
-
- Assert.NotNull(xcode);
- Assert.Contains("partial class XCodePage", xcode, StringComparison.Ordinal);
- Assert.Contains("GetGreeting", xcode, StringComparison.Ordinal);
- Assert.Contains("namespace TestApp", xcode, StringComparison.Ordinal);
- // Verify no using directives in generated code (excluding auto-generated comment lines)
- var nonCommentLines = string.Join("\n", xcode!.Split('\n').Where(l => !l.TrimStart().StartsWith("//")));
- Assert.DoesNotContain("using ", nonCommentLines, StringComparison.Ordinal);
- }
-
- [Fact]
- public void XCode_MultipleBlocks_AreConcatenated()
- {
- var xaml =
-"""
-
-
-
-
- _count++;
- ]]>
-
-""";
-
- var codeBehind =
-"""
-using Microsoft.Maui.Controls;
-using Microsoft.Maui.Controls.Xaml;
-
-namespace TestApp;
-
-[XamlProcessing(XamlInflator.SourceGen)]
-public partial class MultiBlockPage : ContentPage
-{
- public MultiBlockPage() => InitializeComponent();
-}
-""";
-
- var (result, _) = RunGenerator(xaml, codeBehind);
- var xcode = GetXCodeOutput(result);
-
- Assert.NotNull(xcode);
- Assert.Contains("_count", xcode, StringComparison.Ordinal);
- Assert.Contains("Increment", xcode, StringComparison.Ordinal);
- }
-
- [Fact]
- public void XCode_WithoutCDATA_Works()
- {
- var xaml =
-"""
-
-
-
- string Name = "Test";
-
-
-
-""";
-
- var codeBehind =
-"""
-using Microsoft.Maui.Controls;
-using Microsoft.Maui.Controls.Xaml;
-
-namespace TestApp;
-
-[XamlProcessing(XamlInflator.SourceGen)]
-public partial class NoCDataPage : ContentPage
-{
- public NoCDataPage() => InitializeComponent();
-}
-""";
-
- var (result, _) = RunGenerator(xaml, codeBehind);
- var xcode = GetXCodeOutput(result);
-
- Assert.NotNull(xcode);
- Assert.Contains("Name", xcode, StringComparison.Ordinal);
- }
-
- [Fact]
- public void XCode_NoXClass_ReportsDiagnostic()
- {
- var xaml =
-"""
-
-
-
-
-""";
-
- var codeBehind =
-"""
-using Microsoft.Maui.Controls;
-using Microsoft.Maui.Controls.Xaml;
-""";
-
- var (result, _) = RunGenerator(xaml, codeBehind, assertNoCompilationErrors: false);
- Assert.Contains(result.Diagnostics, d => d.Id == "MAUIX2016");
- }
-
- [Fact]
- public void XCode_WithoutPreviewFeatures_ReportsDiagnostic()
- {
- var xaml =
-"""
-
-
-
-
-""";
-
- var codeBehind =
-"""
-using Microsoft.Maui.Controls;
-using Microsoft.Maui.Controls.Xaml;
-
-namespace TestApp;
-
-[XamlProcessing(XamlInflator.SourceGen)]
-public partial class NoPreviewPage : ContentPage
-{
- public NoPreviewPage() => InitializeComponent();
-}
-""";
-
- var (result, _) = RunGenerator(xaml, codeBehind, enablePreviewFeatures: false, assertNoCompilationErrors: false);
- Assert.Contains(result.Diagnostics, d => d.Id == "MAUIX2012");
- }
-
- [Fact]
- public void XCode_NoCodeBlocks_NoOutput()
- {
- var xaml =
-"""
-
-
-
-
-""";
-
- var codeBehind =
-"""
-using Microsoft.Maui.Controls;
-using Microsoft.Maui.Controls.Xaml;
-
-namespace TestApp;
-
-[XamlProcessing(XamlInflator.SourceGen)]
-public partial class NoCodePage : ContentPage
-{
- public NoCodePage() => InitializeComponent();
-}
-""";
-
- var (result, _) = RunGenerator(xaml, codeBehind);
- var xcode = GetXCodeOutput(result);
-
- Assert.Null(xcode);
- }
-
- [Fact]
- public void XCode_UsingDirectives_ArePromotedToFileTop()
- {
- var xaml =
-"""
-
-
- FetchAsync()
- {
- using var client = new HttpClient();
- return await client.GetStringAsync("https://example.com");
- }
- ]]>
-
-
-""";
-
- var codeBehind =
-"""
-using Microsoft.Maui.Controls;
-using Microsoft.Maui.Controls.Xaml;
-
-namespace TestApp;
-
-[XamlProcessing(XamlInflator.SourceGen)]
-public partial class UsingsPage : ContentPage
-{
- public UsingsPage() => InitializeComponent();
-}
-""";
-
- var (result, _) = RunGenerator(xaml, codeBehind);
- var xcode = GetXCodeOutput(result);
-
- Assert.NotNull(xcode);
-
- // using directives should appear before the namespace declaration
- var namespaceIndex = xcode!.IndexOf("namespace TestApp", StringComparison.Ordinal);
- var usingHttpIndex = xcode.IndexOf("using System.Net.Http;", StringComparison.Ordinal);
- var usingTasksIndex = xcode.IndexOf("using System.Threading.Tasks;", StringComparison.Ordinal);
- Assert.True(usingHttpIndex >= 0, "using System.Net.Http should be in output");
- Assert.True(usingTasksIndex >= 0, "using System.Threading.Tasks should be in output");
- Assert.True(usingHttpIndex < namespaceIndex, "using directive should appear before namespace");
- Assert.True(usingTasksIndex < namespaceIndex, "using directive should appear before namespace");
-
- // "using var client" is a using statement, not a directive — it stays inside the class
- var classIndex = xcode.IndexOf("partial class UsingsPage", StringComparison.Ordinal);
- var usingVarIndex = xcode.IndexOf("using var client", StringComparison.Ordinal);
- Assert.True(usingVarIndex > classIndex, "using statement should remain inside the class body");
-
- // Method body should still be present
- Assert.Contains("FetchAsync", xcode, StringComparison.Ordinal);
- }
-
- [Fact]
- public void XCode_DuplicateUsings_AreDeduped()
- {
- var xaml =
-"""
-
-
-
-
-
-
-""";
-
- var codeBehind =
-"""
-using Microsoft.Maui.Controls;
-using Microsoft.Maui.Controls.Xaml;
-
-namespace TestApp;
-
-[XamlProcessing(XamlInflator.SourceGen)]
-public partial class DedupePage : ContentPage
-{
- public DedupePage() => InitializeComponent();
-}
-""";
-
- var (result, _) = RunGenerator(xaml, codeBehind);
- var xcode = GetXCodeOutput(result);
-
- Assert.NotNull(xcode);
- // Should appear exactly once
- var count = xcode!.Split("using System.Net.Http;").Length - 1;
- Assert.Equal(1, count);
- Assert.Contains("Name", xcode, StringComparison.Ordinal);
- }
-
- [Fact]
- public void XCode_UsingStatic_IsPromoted()
- {
- var xaml =
-"""
-
-
- Abs(-42);
- ]]>
-
-
-""";
-
- var codeBehind =
-"""
-using Microsoft.Maui.Controls;
-using Microsoft.Maui.Controls.Xaml;
-
-namespace TestApp;
-
-[XamlProcessing(XamlInflator.SourceGen)]
-public partial class StaticUsingPage : ContentPage
-{
- public StaticUsingPage() => InitializeComponent();
-}
-""";
-
- var (result, _) = RunGenerator(xaml, codeBehind);
- var xcode = GetXCodeOutput(result);
-
- Assert.NotNull(xcode);
- var namespaceIndex = xcode!.IndexOf("namespace TestApp", StringComparison.Ordinal);
- var usingStaticIndex = xcode.IndexOf("using static System.Math;", StringComparison.Ordinal);
- Assert.True(usingStaticIndex >= 0, "using static should be in output");
- Assert.True(usingStaticIndex < namespaceIndex, "using static should appear before namespace");
- Assert.Contains("Compute", xcode, StringComparison.Ordinal);
- }
-}
diff --git a/src/Controls/tests/TestCases.Android.Tests/snapshots/android/ClippedStackLayoutInsideBorderWithBackgroundRendersCorrectly.png b/src/Controls/tests/TestCases.Android.Tests/snapshots/android/ClippedStackLayoutInsideBorderWithBackgroundRendersCorrectly.png
deleted file mode 100644
index 514422386a6f..000000000000
Binary files a/src/Controls/tests/TestCases.Android.Tests/snapshots/android/ClippedStackLayoutInsideBorderWithBackgroundRendersCorrectly.png and /dev/null differ
diff --git a/src/Controls/tests/TestCases.Android.Tests/snapshots/android/EntryAndEditorBackgroundColorShouldResetToDefaultWhenSetToNull.png b/src/Controls/tests/TestCases.Android.Tests/snapshots/android/EntryAndEditorBackgroundColorShouldResetToDefaultWhenSetToNull.png
deleted file mode 100644
index 270dfda8fea8..000000000000
Binary files a/src/Controls/tests/TestCases.Android.Tests/snapshots/android/EntryAndEditorBackgroundColorShouldResetToDefaultWhenSetToNull.png and /dev/null differ
diff --git a/src/Controls/tests/TestCases.Android.Tests/snapshots/android/Issue19690_BackToNormalState.png b/src/Controls/tests/TestCases.Android.Tests/snapshots/android/Issue19690_BackToNormalState.png
deleted file mode 100644
index b77041422d7a..000000000000
Binary files a/src/Controls/tests/TestCases.Android.Tests/snapshots/android/Issue19690_BackToNormalState.png and /dev/null differ
diff --git a/src/Controls/tests/TestCases.Android.Tests/snapshots/android/Issue19690_CustomState.png b/src/Controls/tests/TestCases.Android.Tests/snapshots/android/Issue19690_CustomState.png
deleted file mode 100644
index ed0d3f8819cf..000000000000
Binary files a/src/Controls/tests/TestCases.Android.Tests/snapshots/android/Issue19690_CustomState.png and /dev/null differ
diff --git a/src/Controls/tests/TestCases.Android.Tests/snapshots/android/Issue19690_InitialNormalState.png b/src/Controls/tests/TestCases.Android.Tests/snapshots/android/Issue19690_InitialNormalState.png
deleted file mode 100644
index 7316f79dbb7e..000000000000
Binary files a/src/Controls/tests/TestCases.Android.Tests/snapshots/android/Issue19690_InitialNormalState.png and /dev/null differ
diff --git a/src/Controls/tests/TestCases.Android.Tests/snapshots/android/Issue29772ItemSpaceShouldApply.png b/src/Controls/tests/TestCases.Android.Tests/snapshots/android/Issue29772ItemSpaceShouldApply.png
deleted file mode 100644
index 7337dd8807c2..000000000000
Binary files a/src/Controls/tests/TestCases.Android.Tests/snapshots/android/Issue29772ItemSpaceShouldApply.png and /dev/null differ
diff --git a/src/Controls/tests/TestCases.Android.Tests/snapshots/android/Issue30199TimePickerCharacterSpacingShouldApply.png b/src/Controls/tests/TestCases.Android.Tests/snapshots/android/Issue30199TimePickerCharacterSpacingShouldApply.png
deleted file mode 100644
index 50671f5b3061..000000000000
Binary files a/src/Controls/tests/TestCases.Android.Tests/snapshots/android/Issue30199TimePickerCharacterSpacingShouldApply.png and /dev/null differ
diff --git a/src/Controls/tests/TestCases.Android.Tests/snapshots/android/Issue33783_SwitchThumbColor_DarkTheme.png b/src/Controls/tests/TestCases.Android.Tests/snapshots/android/Issue33783_SwitchThumbColor_DarkTheme.png
deleted file mode 100644
index b9f9a3e36016..000000000000
Binary files a/src/Controls/tests/TestCases.Android.Tests/snapshots/android/Issue33783_SwitchThumbColor_DarkTheme.png and /dev/null differ
diff --git a/src/Controls/tests/TestCases.Android.Tests/snapshots/android/Issue33783_SwitchThumbColor_LightTheme.png b/src/Controls/tests/TestCases.Android.Tests/snapshots/android/Issue33783_SwitchThumbColor_LightTheme.png
deleted file mode 100644
index 7f977a0fbbab..000000000000
Binary files a/src/Controls/tests/TestCases.Android.Tests/snapshots/android/Issue33783_SwitchThumbColor_LightTheme.png and /dev/null differ
diff --git a/src/Controls/tests/TestCases.Android.Tests/snapshots/android/ShouldHideHeaderWhenTitleEmpty.png b/src/Controls/tests/TestCases.Android.Tests/snapshots/android/ShouldHideHeaderWhenTitleEmpty.png
deleted file mode 100644
index e46dbc326f3f..000000000000
Binary files a/src/Controls/tests/TestCases.Android.Tests/snapshots/android/ShouldHideHeaderWhenTitleEmpty.png and /dev/null differ
diff --git a/src/Controls/tests/TestCases.Android.Tests/snapshots/android/ShouldShowHeaderWhenTitleNotEmpty.png b/src/Controls/tests/TestCases.Android.Tests/snapshots/android/ShouldShowHeaderWhenTitleNotEmpty.png
deleted file mode 100644
index 7709750eeab6..000000000000
Binary files a/src/Controls/tests/TestCases.Android.Tests/snapshots/android/ShouldShowHeaderWhenTitleNotEmpty.png and /dev/null differ
diff --git a/src/Controls/tests/TestCases.Android.Tests/snapshots/android/TimePickerFlowDirectionTest.png b/src/Controls/tests/TestCases.Android.Tests/snapshots/android/TimePickerFlowDirectionTest.png
deleted file mode 100644
index be2aa44a6459..000000000000
Binary files a/src/Controls/tests/TestCases.Android.Tests/snapshots/android/TimePickerFlowDirectionTest.png and /dev/null differ
diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Issue19690.cs b/src/Controls/tests/TestCases.HostApp/Issues/Issue19690.cs
deleted file mode 100644
index f3321c210106..000000000000
--- a/src/Controls/tests/TestCases.HostApp/Issues/Issue19690.cs
+++ /dev/null
@@ -1,114 +0,0 @@
-using Microsoft.Maui.Controls;
-using Microsoft.Maui.Graphics;
-
-namespace Maui.Controls.Sample.Issues;
-
-[Issue(IssueTracker.Github, 19690, "Button VisualStates do not work", PlatformAffected.iOS | PlatformAffected.Android | PlatformAffected.macOS)]
-public class Issue19690 : ContentPage
-{
- const string CustomStateName = "Custom";
-
- public Issue19690()
- {
- var button = new Issue19690CustomButton
- {
- Text = "Click Me",
- AutomationId = "TestButton"
- };
-
- var statusLabel = new Label
- {
- Text = "Initial State",
- AutomationId = "StatusLabel",
- HorizontalOptions = LayoutOptions.Center,
- Margin = new Thickness(0, 20, 0, 0)
- };
-
- button.Clicked += (s, e) =>
- {
- statusLabel.Text = button.IsCustom ? "Custom State" : "Normal State";
- };
-
- Content = new VerticalStackLayout
- {
- Padding = 20,
- Children =
- {
- new Label
- {
- Text = "Click the button multiple times. The button should toggle between Normal (default colors) and Custom (Purple background, Yellow text) states.",
- AutomationId = "InstructionLabel"
- },
- button,
- statusLabel
- }
- };
- }
-
- class Issue19690CustomButton : Button
- {
- public static readonly BindableProperty IsCustomProperty =
- BindableProperty.Create(nameof(IsCustom), typeof(bool), typeof(Issue19690CustomButton), false, propertyChanged: OnIsCustomChanged);
-
- public bool IsCustom
- {
- get => (bool)GetValue(IsCustomProperty);
- set => SetValue(IsCustomProperty, value);
- }
-
- public Issue19690CustomButton()
- {
- var visualStateGroups = new VisualStateGroupList();
- var commonStates = new VisualStateGroup { Name = "CommonStates" };
-
- commonStates.States.Add(new VisualState { Name = "Normal" });
- commonStates.States.Add(new VisualState { Name = "Disabled" });
- commonStates.States.Add(new VisualState { Name = "PointerOver" });
- commonStates.States.Add(new VisualState { Name = "Pressed" });
- commonStates.States.Add(new VisualState { Name = "Focused" });
-
- var customState = new VisualState { Name = CustomStateName };
- customState.Setters.Add(new Setter
- {
- Property = TextColorProperty,
- Value = Colors.Blue
- });
- customState.Setters.Add(new Setter
- {
- Property = BackgroundColorProperty,
- Value = Colors.Purple
- });
- commonStates.States.Add(customState);
-
- visualStateGroups.Add(commonStates);
- VisualStateManager.SetVisualStateGroups(this, visualStateGroups);
-
- Clicked += OnButtonClicked;
- }
-
- void OnButtonClicked(object sender, EventArgs e)
- {
- IsCustom = !IsCustom;
- }
-
- protected internal override void ChangeVisualState()
- {
- if (IsCustom && IsEnabled)
- {
- VisualStateManager.GoToState(this, CustomStateName);
- }
- else
- {
- base.ChangeVisualState();
- }
- }
-
- static void OnIsCustomChanged(BindableObject bindable, object oldValue, object newValue)
- {
- if (bindable is Issue19690CustomButton button)
- {
- button.ChangeVisualState();
- }
- }
- }
-}
diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Issue19866.cs b/src/Controls/tests/TestCases.HostApp/Issues/Issue19866.cs
deleted file mode 100644
index 1600df5208a2..000000000000
--- a/src/Controls/tests/TestCases.HostApp/Issues/Issue19866.cs
+++ /dev/null
@@ -1,33 +0,0 @@
-namespace Maui.Controls.Sample.Issues;
-
-[Issue(IssueTracker.Github, 19866, "CollectionView does not scroll to top on iOS status bar tap", PlatformAffected.iOS)]
-public class Issue19866 : TestShell
-{
- protected override void Init()
- {
- var items = Enumerable.Range(0, 100).Select(i => $"Item {i}").ToList();
-
- var collectionView = new CollectionView
- {
- AutomationId = "TestCollectionView",
- ItemsSource = items,
- ItemTemplate = new DataTemplate(() =>
- {
- var label = new Label
- {
- Margin = new Thickness(10, 20),
- FontSize = 16
- };
- label.SetBinding(Label.TextProperty, new Binding("."));
- label.SetBinding(Label.AutomationIdProperty, new Binding("."));
- return label;
- })
- };
-
- AddContentPage(new ContentPage
- {
- Title = "Issue 19866",
- Content = collectionView
- });
- }
-}
diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Issue29529.cs b/src/Controls/tests/TestCases.HostApp/Issues/Issue29529.cs
deleted file mode 100644
index 14ffbcd056c7..000000000000
--- a/src/Controls/tests/TestCases.HostApp/Issues/Issue29529.cs
+++ /dev/null
@@ -1,113 +0,0 @@
-using System.Collections.ObjectModel;
-
-namespace Maui.Controls.Sample.Issues;
-
-[Issue(IssueTracker.Github, 29529, "CurrentItemChangedEventArgs and PositionChangedEventArgs Not Updating Correctly in CarouselView", PlatformAffected.UWP | PlatformAffected.Android)]
-public class Issue29529 : ContentPage
-{
- int _positionChangedCount = 0;
- int _currentItemChangedCount = 0;
-
- public Issue29529()
- {
- var verticalStackLayout = new VerticalStackLayout();
- var carouselItems = new ObservableCollection
- {
- "Item 1",
- "Item 2",
- "Item 3",
- "Item 4",
- "Item 5",
- "Item 6",
- };
-
- CarouselView carouselView = new CarouselView
- {
- ItemsSource = carouselItems,
- AutomationId = "carouselview",
- Position = 3,
- ItemsUpdatingScrollMode = ItemsUpdatingScrollMode.KeepItemsInView,
- Loop = false,
- HeightRequest = 300,
- ItemTemplate = new DataTemplate(() =>
- {
- var grid = new Grid
- {
- Padding = 10
- };
-
- var label = new Label
- {
- VerticalOptions = LayoutOptions.Center,
- HorizontalOptions = LayoutOptions.Center,
- FontSize = 18,
- };
- label.SetBinding(Label.TextProperty, ".");
- label.SetBinding(Label.AutomationIdProperty, ".");
-
- grid.Children.Add(label);
- return grid;
- }),
- HorizontalOptions = LayoutOptions.Fill,
- };
-
- var positionLabel = new Label
- {
- AutomationId = "positionLabel",
- Text = $"Current Position: {carouselView.Position}",
- HorizontalOptions = LayoutOptions.Center,
- Padding = new Thickness(20),
- };
-
- var itemLabel = new Label
- {
- AutomationId = "itemLabel",
- Text = $"Current Item: {carouselView.CurrentItem}",
- HorizontalOptions = LayoutOptions.Center,
- Padding = new Thickness(20),
- };
-
- var eventCountLabel = new Label
- {
- AutomationId = "eventCountLabel",
- Text = "PositionChanged: 0, CurrentItemChanged: 0",
- HorizontalOptions = LayoutOptions.Center,
- Padding = new Thickness(20),
- };
-
- carouselView.PositionChanged += (s, e) =>
- {
- _positionChangedCount++;
- positionLabel.Text = $"Current Position: {e.CurrentPosition}, Previous Position: {e.PreviousPosition}";
- eventCountLabel.Text = $"PositionChanged: {_positionChangedCount}, CurrentItemChanged: {_currentItemChangedCount}";
- };
-
- carouselView.CurrentItemChanged += (s, e) =>
- {
- _currentItemChangedCount++;
- itemLabel.Text = $"Current Item: {e.CurrentItem}, Previous Item: {e.PreviousItem}";
- eventCountLabel.Text = $"PositionChanged: {_positionChangedCount}, CurrentItemChanged: {_currentItemChangedCount}";
- };
-
- var insertButton = new Button
- {
- Text = "Insert item at index 0",
- AutomationId = "InsertButton",
- Margin = new Thickness(20),
- };
-
- insertButton.Clicked += (sender, e) =>
- {
- _positionChangedCount = 0;
- _currentItemChangedCount = 0;
- carouselItems.Insert(0, "Item 0");
- };
-
- verticalStackLayout.Children.Add(carouselView);
- verticalStackLayout.Children.Add(insertButton);
- verticalStackLayout.Children.Add(positionLabel);
- verticalStackLayout.Children.Add(itemLabel);
- verticalStackLayout.Children.Add(eventCountLabel);
- Content = verticalStackLayout;
- }
-}
diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Issue29772.cs b/src/Controls/tests/TestCases.HostApp/Issues/Issue29772.cs
deleted file mode 100644
index 563533dbd041..000000000000
--- a/src/Controls/tests/TestCases.HostApp/Issues/Issue29772.cs
+++ /dev/null
@@ -1,80 +0,0 @@
-using System.Collections.ObjectModel;
-
-namespace Controls.TestCases.HostApp.Issues;
-
-[Issue(IssueTracker.Github, 29772, "ItemSpacing doesnot work on CarouselView", PlatformAffected.UWP)]
-public class Issue29772 : ContentPage
-{
- Issue29772_ViewModel ViewModel;
- CarouselView carouselView;
- public Issue29772()
- {
- ViewModel = new Issue29772_ViewModel();
- BindingContext = ViewModel;
- var stack = new StackLayout();
-
- var descriptionlabel = new Label
- {
- Text = "ItemSpacing Should apply between items on CarouselView",
- HorizontalTextAlignment = TextAlignment.Center,
- AutomationId = "29772DescriptionLabel"
- };
-
- carouselView = new CarouselView
- {
- BackgroundColor = Colors.Green,
- HeightRequest = 400,
- WidthRequest = 300,
- ItemsSource = ViewModel.Items,
- Loop = false,
- CurrentItem = "Item 0",
- PeekAreaInsets = new Thickness(20, 0, 20, 0),
- HorizontalScrollBarVisibility = ScrollBarVisibility.Never,
- ItemsLayout = new LinearItemsLayout(ItemsLayoutOrientation.Horizontal)
- {
- ItemSpacing = 10,
- SnapPointsAlignment = SnapPointsAlignment.Center,
- SnapPointsType = SnapPointsType.MandatorySingle,
- },
-
- ItemTemplate = new DataTemplate(() =>
- {
- var grid = new Grid
- {
- Margin = 0,
- Padding = 0,
- BackgroundColor = Colors.Yellow
- };
-
- var label = new Label
- {
- FontSize = 24,
- HorizontalOptions = LayoutOptions.Center,
- VerticalOptions = LayoutOptions.Center
- };
- label.SetBinding(Label.TextProperty, ".");
-
- grid.Children.Add(label);
- return grid;
- })
- };
-
- stack.Children.Add(descriptionlabel);
- stack.Children.Add(carouselView);
- Content = stack;
- }
-}
-
-public class Issue29772_ViewModel
-{
- public ObservableCollection Items { get; set; }
-
- public Issue29772_ViewModel()
- {
- Items = new ObservableCollection();
- for (var i = 0; i < 4; i++)
- {
- Items.Add($"Item {i}");
- }
- }
-}
\ No newline at end of file
diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Issue30192.cs b/src/Controls/tests/TestCases.HostApp/Issues/Issue30192.cs
deleted file mode 100644
index d348eb7f1224..000000000000
--- a/src/Controls/tests/TestCases.HostApp/Issues/Issue30192.cs
+++ /dev/null
@@ -1,43 +0,0 @@
-namespace Maui.Controls.Sample.Issues;
-
-[Issue(IssueTracker.Github, 30192, "TimePicker FlowDirection Not Working on All Platforms", PlatformAffected.All)]
-public class Issue30192 : ContentPage
-{
- public Issue30192()
- {
- TimePicker ltrTimePicker = new TimePicker
- {
- Time = new TimeSpan(2, 0, 0),
- Format = "hh:mm tt",
- FlowDirection = FlowDirection.LeftToRight,
- };
-
- TimePicker rtlTimePicker = new TimePicker
- {
- Time = new TimeSpan(2, 0, 0),
- Format = "hh:mm tt",
- FlowDirection = FlowDirection.RightToLeft,
- };
-
- Button button = new Button
- {
- Text = "Toggle FlowDirection",
- AutomationId = "ToggleFlowDirectionButton"
- };
- button.Clicked += (sender, e) =>
- {
- ltrTimePicker.FlowDirection = FlowDirection.RightToLeft;
- rtlTimePicker.FlowDirection = FlowDirection.LeftToRight;
- };
-
- Content = new VerticalStackLayout
- {
- Children =
- {
- ltrTimePicker,
- rtlTimePicker,
- button
- }
- };
- }
-}
\ No newline at end of file
diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Issue30199.cs b/src/Controls/tests/TestCases.HostApp/Issues/Issue30199.cs
deleted file mode 100644
index e579e669dd84..000000000000
--- a/src/Controls/tests/TestCases.HostApp/Issues/Issue30199.cs
+++ /dev/null
@@ -1,34 +0,0 @@
-namespace Maui.Controls.Sample.Issues;
-
-[Issue(IssueTracker.Github, "30199", "TimePicker CharacterSpacing Property Not Working on Windows", PlatformAffected.UWP)]
-
-public class Issue30199 : ContentPage
-{
- public Issue30199()
- {
- var label = new Label
- {
- AutomationId = "label",
- Text = "Test passes if TimePicker has character Spacing",
- HorizontalOptions = LayoutOptions.Center,
- VerticalOptions = LayoutOptions.Center,
- };
-
- var timePicker = new TimePicker
- {
- AutomationId = "timePicker",
- Time = new TimeSpan(12, 30, 0),
- CharacterSpacing = 10,
- HorizontalOptions = LayoutOptions.Center,
- VerticalOptions = LayoutOptions.Center,
- Format = "HH:mm"
- };
-
- Content = new StackLayout
- {
- Children = { label, timePicker },
- Spacing = 20,
- Margin = new Thickness(20)
- };
- }
-}
\ No newline at end of file
diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Issue30254.cs b/src/Controls/tests/TestCases.HostApp/Issues/Issue30254.cs
deleted file mode 100644
index 04cf2b85ba3d..000000000000
--- a/src/Controls/tests/TestCases.HostApp/Issues/Issue30254.cs
+++ /dev/null
@@ -1,77 +0,0 @@
-namespace Maui.Controls.Sample.Issues;
-
-[Issue(IssueTracker.Github, 30254, "(Windows) Shell.FlyoutBehavior=Flyout forces the title height space above the tab bar even if the page title is empty", PlatformAffected.UWP)]
-public class Issue30254 : Shell
-{
- public Issue30254()
- {
- BackgroundColor = Colors.Blue;
- FlyoutBehavior = FlyoutBehavior.Flyout;
-
- var goToWithTitleButton = new Button
- {
- AutomationId = "GoToWithTitleButton",
- Text = "Go to page with title",
- HorizontalOptions = LayoutOptions.Center,
- VerticalOptions = LayoutOptions.Center,
- };
- goToWithTitleButton.Clicked += (s, e) => GoToAsync("//WithTitleTab");
-
- var pageWithEmptyTitle = new ContentPage
- {
- Title = "",
- Content = new VerticalStackLayout
- {
- VerticalOptions = LayoutOptions.Center,
- Children =
- {
- new Label
- {
- AutomationId = "MainPageLabel",
- Text = "This page has an empty title.",
- HorizontalOptions = LayoutOptions.Center,
- },
- goToWithTitleButton
- }
- }
- };
-
- var goToEmptyTitleButton = new Button
- {
- AutomationId = "GoToEmptyTitleButton",
- Text = "Go to page with empty title",
- HorizontalOptions = LayoutOptions.Center,
- VerticalOptions = LayoutOptions.Center,
- };
- goToEmptyTitleButton.Clicked += (s, e) => GoToAsync("//EmptyTitleTab");
-
- var pageWithTitle = new ContentPage
- {
- Title = "Page With Title",
- Content = new VerticalStackLayout
- {
- VerticalOptions = LayoutOptions.Center,
- Children =
- {
- new Label
- {
- AutomationId = "WithTitleLabel",
- Text = "This page has a title, so header space is expected.",
- HorizontalOptions = LayoutOptions.Center,
- },
- goToEmptyTitleButton
- }
- }
- };
-
- Items.Add(new FlyoutItem
- {
- Title = "Header Test",
- Items =
- {
- new ShellContent { Title = "Empty Title", AutomationId = "EmptyTitleTab", Route = "EmptyTitleTab", Content = pageWithEmptyTitle },
- new ShellContent { Title = "With Title", AutomationId = "WithTitleTab", Route = "WithTitleTab", Content = pageWithTitle },
- }
- });
- }
-}
diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Issue32971.cs b/src/Controls/tests/TestCases.HostApp/Issues/Issue32971.cs
deleted file mode 100644
index 84232f879694..000000000000
--- a/src/Controls/tests/TestCases.HostApp/Issues/Issue32971.cs
+++ /dev/null
@@ -1,72 +0,0 @@
-namespace Maui.Controls.Sample.Issues;
-
-[Issue(IssueTracker.Github, 32971, "WebView content does not scroll when placed inside a ScrollView", PlatformAffected.Android)]
-public class Issue32971 : ContentPage
-{
- public Issue32971()
- {
- Label _scrollStateLabel = new Label
- {
- Text = "NotScrolled",
- AutomationId = "ScrollStateLabel",
- FontSize = 20,
- HorizontalTextAlignment = TextAlignment.Center,
- };
-
- WebView _webView = new WebView
- {
- AutomationId = "TestWebView",
- HeightRequest = 600,
- VerticalOptions = LayoutOptions.Start,
- };
-
- _webView.Source = new HtmlWebViewSource
- {
- Html = @"
-
-
-
-
-
-
-
- WebView Scrolling Test
- Section 1 Scroll down to test...
- Section 2 Keep scrolling...
-
-
-
-
- "
- };
-
- var checkButton = new Button
- {
- Text = "Check Scroll State",
- AutomationId = "CheckButton",
- };
-
- checkButton.Clicked += async (s, e) =>
- {
- var result = await _webView.EvaluateJavaScriptAsync("Math.round(window.pageYOffset);");
- if (int.TryParse(result, out int scrollPos) && scrollPos > 50)
- {
- _scrollStateLabel.Text = "Scrolled";
- }
- };
-
- var scrollView = new ScrollView
- {
- AutomationId = "TestScrollView",
- Content = new VerticalStackLayout
- {
- Children = { _scrollStateLabel, checkButton, _webView }
- }
- };
-
- Content = scrollView;
- }
-}
\ No newline at end of file
diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Issue33241.cs b/src/Controls/tests/TestCases.HostApp/Issues/Issue33241.cs
deleted file mode 100644
index 21bb9b260887..000000000000
--- a/src/Controls/tests/TestCases.HostApp/Issues/Issue33241.cs
+++ /dev/null
@@ -1,38 +0,0 @@
-using Microsoft.Maui.Controls.Shapes;
-namespace Maui.Controls.Sample.Issues;
-
-[Issue(IssueTracker.Github, 33241, "StackLayout fails to render content while applying Clip, and the layout is placed inside a Border with Background", PlatformAffected.iOS | PlatformAffected.macOS)]
-public class Issue33241 : ContentPage
-{
- public Issue33241()
- {
- var layout = new VerticalStackLayout();
- var label = new Label();
- label.Text = "The blue box should have a red box inside of it.";
- label.AutomationId = "Label";
- layout.Children.Add(label);
- var border = new Border
- {
- HeightRequest = 500,
- Background = Colors.SkyBlue,
- Padding = 10,
- Content =
- new Issue33241_CustomView
- {
- Background = Colors.Red,
- Padding = 10
- }
- };
- layout.Children.Add(border);
- Content = layout;
- }
-}
-
-public class Issue33241_CustomView : StackLayout
-{
- protected override void OnSizeAllocated(double width, double height)
- {
- this.Clip = new RoundRectangleGeometry { Rect = new Rect(0, 0, width, height) };
- base.OnSizeAllocated(width, height);
- }
-}
\ No newline at end of file
diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Issue33783.cs b/src/Controls/tests/TestCases.HostApp/Issues/Issue33783.cs
deleted file mode 100644
index f15fea30b246..000000000000
--- a/src/Controls/tests/TestCases.HostApp/Issues/Issue33783.cs
+++ /dev/null
@@ -1,61 +0,0 @@
-namespace Maui.Controls.Sample.Issues;
-
-[Issue(IssueTracker.Github, 33783, "Switch ThumbColor not applied correctly when theme changes on iOS", PlatformAffected.iOS | PlatformAffected.macOS)]
-public class Issue33783 : ContentPage
-{
- public Issue33783()
- {
- var testSwitch = new Switch
- {
- AutomationId = "TestSwitch",
- OnColor = Colors.Green,
- ThumbColor = Colors.Red,
- IsToggled = true,
- HorizontalOptions = LayoutOptions.Center
- };
-
- var lightThemeButton = new Button
- {
- AutomationId = "LightThemeButton",
- Text = "Light Theme"
- };
-
- lightThemeButton.Clicked += (s, e) =>
- {
- if (Application.Current != null)
- {
- Application.Current.UserAppTheme = AppTheme.Light;
- }
- };
-
- var darkThemeButton = new Button
- {
- AutomationId = "DarkThemeButton",
- Text = "Dark Theme"
- };
-
- darkThemeButton.Clicked += (s, e) =>
- {
- if (Application.Current != null)
- {
- Application.Current.UserAppTheme = AppTheme.Dark;
- }
- };
-
- var themeButtonsLayout = new HorizontalStackLayout
- {
- Spacing = 10,
- HorizontalOptions = LayoutOptions.Center,
- Children = { lightThemeButton, darkThemeButton }
- };
-
- var contentLayout = new VerticalStackLayout
- {
- Spacing = 20,
- Padding = new Thickness(30),
- Children = { testSwitch, themeButtonsLayout }
- };
- contentLayout.SetAppThemeColor(BackgroundColorProperty, Colors.White, Colors.Black);
- Content = contentLayout;
- }
-}
\ No newline at end of file
diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Issue34611.cs b/src/Controls/tests/TestCases.HostApp/Issues/Issue34611.cs
deleted file mode 100644
index ffebf3646916..000000000000
--- a/src/Controls/tests/TestCases.HostApp/Issues/Issue34611.cs
+++ /dev/null
@@ -1,69 +0,0 @@
-namespace Maui.Controls.Sample.Issues;
-
-[Issue(IssueTracker.Github, 34611, "Entry and Editor BackgroundColor not reset to Null", PlatformAffected.iOS | PlatformAffected.macOS)]
-public class Issue34611 : TestContentPage
-{
- Entry _entry;
- Editor _editor;
-
- protected override void Init()
- {
- Title = "Issue34611";
-
- _entry = new Entry
- {
- AutomationId = "TestEntry",
- Text = "Entry background should reset",
- Placeholder = "Entry"
- };
-
- _editor = new Editor
- {
- AutomationId = "TestEditor",
- Text = "Editor background should reset",
- HeightRequest = 120,
- Placeholder = "Editor"
- };
-
- var applyButton = new Button
- {
- AutomationId = "ApplyBackgroundColorButton",
- Text = "Apply BackgroundColor"
- };
-
- applyButton.Clicked += (_, _) =>
- {
- _entry.BackgroundColor = Colors.Red;
- _editor.BackgroundColor = Colors.LightBlue;
- };
-
- var resetButton = new Button
- {
- AutomationId = "ResetToDefaultButton",
- Text = "Reset to Default"
- };
-
- resetButton.Clicked += (_, _) =>
- {
- _entry.BackgroundColor = null;
- _editor.BackgroundColor = null;
- };
-
- Content = new VerticalStackLayout
- {
- Margin = new Thickness(20, 0, 20, 0),
- Spacing = 12,
- Children =
- {
- new Label
- {
- Text = "Apply custom backgrounds, then reset them to null."
- },
- _entry,
- _editor,
- applyButton,
- resetButton
- }
- };
- }
-}
diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Issue34783.cs b/src/Controls/tests/TestCases.HostApp/Issues/Issue34783.cs
deleted file mode 100644
index 4b8d3fba9f15..000000000000
--- a/src/Controls/tests/TestCases.HostApp/Issues/Issue34783.cs
+++ /dev/null
@@ -1,136 +0,0 @@
-using System.Collections.ObjectModel;
-
-namespace Maui.Controls.Sample.Issues;
-
-[Issue(IssueTracker.Github, 34783, "CollectionView Dynamic item sizing - After dragging the scrollbar all images return to their original size", PlatformAffected.Android)]
-public class Issue34783 : ContentPage
-{
- public Issue34783()
- {
- BindingContext = new Issue34783ViewModel();
-
- var grid = new Grid
- {
- Margin = new Thickness(20),
- RowDefinitions = new RowDefinitionCollection
- {
- new RowDefinition { Height = GridLength.Auto },
- new RowDefinition { Height = GridLength.Auto },
- new RowDefinition { Height = GridLength.Star }
- }
- };
-
- var instructions = new StackLayout
- {
- Children =
- {
- new Label { Text = "1. Confirm that the CollectionView below is populated with monkeys and can be scrolled." },
- new Label { Text = "2. Tap an image to dynamically change its size, then scroll it off-screen and back on-screen. The test passes if the resized image stays resized." }
- }
- };
-
- var tapLabel = new Label { Text = "Tap each image to dynamically change its size." };
-
- var itemTemplate = new DataTemplate(() =>
- {
- var innerGrid = new Grid { Padding = new Thickness(10) };
- innerGrid.RowDefinitions.Add(new RowDefinition { Height = GridLength.Auto });
- innerGrid.RowDefinitions.Add(new RowDefinition { Height = GridLength.Auto });
- innerGrid.ColumnDefinitions.Add(new ColumnDefinition { Width = GridLength.Auto });
- innerGrid.ColumnDefinitions.Add(new ColumnDefinition { Width = GridLength.Star });
-
- var image = new Image
- {
- Aspect = Aspect.AspectFill,
- HeightRequest = 60,
- WidthRequest = 60
- };
- image.SetBinding(Image.SourceProperty, new Binding("ImageUrl"));
- image.SetBinding(Image.AutomationIdProperty, new Binding("Name"));
-
- var tapGesture = new TapGestureRecognizer();
- tapGesture.Tapped += OnImageTapped;
- image.GestureRecognizers.Add(tapGesture);
-
- Grid.SetRowSpan(image, 2);
-
- var nameLabel = new Label { FontAttributes = FontAttributes.Bold };
- nameLabel.SetBinding(Label.TextProperty, new Binding("Name"));
- Grid.SetColumn(nameLabel, 1);
-
- var locationLabel = new Label
- {
- FontAttributes = FontAttributes.Italic,
- VerticalOptions = LayoutOptions.End
- };
- locationLabel.SetBinding(Label.TextProperty, new Binding("Location"));
- Grid.SetRow(locationLabel, 1);
- Grid.SetColumn(locationLabel, 1);
-
- innerGrid.Children.Add(image);
- innerGrid.Children.Add(nameLabel);
- innerGrid.Children.Add(locationLabel);
-
- return innerGrid;
- });
-
- var collectionView = new CollectionView
- {
- AutomationId = "Issue34783CollectionView",
- ItemTemplate = itemTemplate
- };
- collectionView.SetBinding(CollectionView.ItemsSourceProperty, new Binding("Monkeys"));
-
- Grid.SetRow(tapLabel, 1);
- Grid.SetRow(collectionView, 2);
-
- grid.Children.Add(instructions);
- grid.Children.Add(tapLabel);
- grid.Children.Add(collectionView);
-
- Content = grid;
- }
-
- void OnImageTapped(object sender, EventArgs e)
- {
- if (sender is Image image)
- image.HeightRequest = image.WidthRequest = image.HeightRequest.Equals(60) ? 100 : 60;
- }
-}
-
-public class Issue34783Monkey
-{
- public string Name { get; set; }
- public string Location { get; set; }
- public string Details { get; set; }
- public string ImageUrl { get; set; }
-}
-
-public class Issue34783ViewModel
-{
- public ObservableCollection Monkeys { get; set; }
-
- public Issue34783ViewModel()
- {
- Monkeys = new ObservableCollection
- {
- new Issue34783Monkey { Name = "Baboon", Location = "Africa & Asia", ImageUrl = "papio.jpg" },
- new Issue34783Monkey { Name = "Capuchin Monkey", Location = "Central & South America", ImageUrl = "capuchin.jpg" },
- new Issue34783Monkey { Name = "Blue Monkey", Location = "Central and East Africa", ImageUrl = "bluemonkey.jpg" },
- new Issue34783Monkey { Name = "Squirrel Monkey", Location = "Central & South America", ImageUrl = "saimiri.jpg" },
- new Issue34783Monkey { Name = "Golden Lion Tamarin", Location = "Brazil", ImageUrl = "golden.jpg" },
- new Issue34783Monkey { Name = "Howler Monkey", Location = "South America", ImageUrl = "alouatta.jpg" },
- new Issue34783Monkey { Name = "Japanese Macaque", Location = "Japan", ImageUrl = "papio.jpg" },
- new Issue34783Monkey { Name = "Mandrill", Location = "Central Africa", ImageUrl = "capuchin.jpg" },
- new Issue34783Monkey { Name = "Proboscis Monkey", Location = "Borneo", ImageUrl = "bluemonkey.jpg" },
- new Issue34783Monkey { Name = "Red-shanked Douc", Location = "Vietnam, Laos", ImageUrl = "saimiri.jpg" },
- new Issue34783Monkey { Name = "Gray-shanked Douc", Location = "Vietnam", ImageUrl = "golden.jpg" },
- new Issue34783Monkey { Name = "Snub-nosed Monkey", Location = "China", ImageUrl = "alouatta.jpg" },
- new Issue34783Monkey { Name = "Black Snub-nosed", Location = "China", ImageUrl = "papio.jpg" },
- new Issue34783Monkey { Name = "Tonkin Monkey", Location = "Vietnam", ImageUrl = "capuchin.jpg" },
- new Issue34783Monkey { Name = "Thomas Langur", Location = "Indonesia", ImageUrl = "bluemonkey.jpg" },
- new Issue34783Monkey { Name = "Purple-faced Langur", Location = "Sri Lanka", ImageUrl = "saimiri.jpg" },
- new Issue34783Monkey { Name = "Gelada", Location = "Ethiopia", ImageUrl = "golden.jpg" },
- };
- }
-}
diff --git a/src/Controls/tests/TestCases.Mac.Tests/snapshots/mac/EntryAndEditorBackgroundColorShouldResetToDefaultWhenSetToNull.png b/src/Controls/tests/TestCases.Mac.Tests/snapshots/mac/EntryAndEditorBackgroundColorShouldResetToDefaultWhenSetToNull.png
deleted file mode 100644
index 0c9a08b394e6..000000000000
Binary files a/src/Controls/tests/TestCases.Mac.Tests/snapshots/mac/EntryAndEditorBackgroundColorShouldResetToDefaultWhenSetToNull.png and /dev/null differ
diff --git a/src/Controls/tests/TestCases.Mac.Tests/snapshots/mac/Issue19690_BackToNormalState.png b/src/Controls/tests/TestCases.Mac.Tests/snapshots/mac/Issue19690_BackToNormalState.png
deleted file mode 100644
index 5df4cef9581c..000000000000
Binary files a/src/Controls/tests/TestCases.Mac.Tests/snapshots/mac/Issue19690_BackToNormalState.png and /dev/null differ
diff --git a/src/Controls/tests/TestCases.Mac.Tests/snapshots/mac/Issue19690_CustomState.png b/src/Controls/tests/TestCases.Mac.Tests/snapshots/mac/Issue19690_CustomState.png
deleted file mode 100644
index f8cbe26be0fe..000000000000
Binary files a/src/Controls/tests/TestCases.Mac.Tests/snapshots/mac/Issue19690_CustomState.png and /dev/null differ
diff --git a/src/Controls/tests/TestCases.Mac.Tests/snapshots/mac/Issue19690_InitialNormalState.png b/src/Controls/tests/TestCases.Mac.Tests/snapshots/mac/Issue19690_InitialNormalState.png
deleted file mode 100644
index 43aa1cf6307a..000000000000
Binary files a/src/Controls/tests/TestCases.Mac.Tests/snapshots/mac/Issue19690_InitialNormalState.png and /dev/null differ
diff --git a/src/Controls/tests/TestCases.Mac.Tests/snapshots/mac/Issue29772ItemSpaceShouldApply.png b/src/Controls/tests/TestCases.Mac.Tests/snapshots/mac/Issue29772ItemSpaceShouldApply.png
deleted file mode 100644
index dfc1621d7e5f..000000000000
Binary files a/src/Controls/tests/TestCases.Mac.Tests/snapshots/mac/Issue29772ItemSpaceShouldApply.png and /dev/null differ
diff --git a/src/Controls/tests/TestCases.Mac.Tests/snapshots/mac/Issue33783_SwitchThumbColor_DarkTheme.png b/src/Controls/tests/TestCases.Mac.Tests/snapshots/mac/Issue33783_SwitchThumbColor_DarkTheme.png
deleted file mode 100644
index 4970767edb25..000000000000
Binary files a/src/Controls/tests/TestCases.Mac.Tests/snapshots/mac/Issue33783_SwitchThumbColor_DarkTheme.png and /dev/null differ
diff --git a/src/Controls/tests/TestCases.Mac.Tests/snapshots/mac/Issue33783_SwitchThumbColor_LightTheme.png b/src/Controls/tests/TestCases.Mac.Tests/snapshots/mac/Issue33783_SwitchThumbColor_LightTheme.png
deleted file mode 100644
index 2905f8c2b459..000000000000
Binary files a/src/Controls/tests/TestCases.Mac.Tests/snapshots/mac/Issue33783_SwitchThumbColor_LightTheme.png and /dev/null differ
diff --git a/src/Controls/tests/TestCases.Mac.Tests/snapshots/mac/ShouldHideHeaderWhenTitleEmpty.png b/src/Controls/tests/TestCases.Mac.Tests/snapshots/mac/ShouldHideHeaderWhenTitleEmpty.png
deleted file mode 100644
index 87ca549b7989..000000000000
Binary files a/src/Controls/tests/TestCases.Mac.Tests/snapshots/mac/ShouldHideHeaderWhenTitleEmpty.png and /dev/null differ
diff --git a/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue19690.cs b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue19690.cs
deleted file mode 100644
index 0c25f17f6e70..000000000000
--- a/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue19690.cs
+++ /dev/null
@@ -1,33 +0,0 @@
-using NUnit.Framework;
-using UITest.Appium;
-using UITest.Core;
-
-namespace Microsoft.Maui.TestCases.Tests.Issues;
-
-public class Issue19690 : _IssuesUITest
-{
- public Issue19690(TestDevice device) : base(device) { }
-
- public override string Issue => "Button VisualStates do not work";
-
- [Test]
- [Category(UITestCategories.Button)]
- public void ButtonVisualStatesShouldToggleBetweenNormalAndCustom()
- {
- App.WaitForElement("TestButton");
-
- Exception? exception = null;
- VerifyScreenshotOrSetException(ref exception, "Issue19690_InitialNormalState");
-
- App.Tap("TestButton");
- VerifyScreenshotOrSetException(ref exception, "Issue19690_CustomState");
-
- App.Tap("TestButton");
- VerifyScreenshotOrSetException(ref exception, "Issue19690_BackToNormalState");
-
- if (exception != null)
- {
- throw exception;
- }
- }
-}
diff --git a/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue19866.cs b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue19866.cs
deleted file mode 100644
index 631769b10c8d..000000000000
--- a/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue19866.cs
+++ /dev/null
@@ -1,37 +0,0 @@
-#if IOS
-using NUnit.Framework;
-using UITest.Appium;
-using UITest.Core;
-
-namespace Microsoft.Maui.TestCases.Tests.Issues;
-
-public class Issue19866 : _IssuesUITest
-{
- public Issue19866(TestDevice testDevice) : base(testDevice) { }
-
- public override string Issue => "CollectionView does not scroll to top on iOS status bar tap";
-
- [Test]
- [Category(UITestCategories.CollectionView)]
- public void StatusBarTapScrollsCollectionViewToTop()
- {
- // Verify first item is visible initially
- App.WaitForElement("Item 0");
-
- // Scroll down multiple times to move well past the first item
- App.ScrollDown("TestCollectionView", ScrollStrategy.Gesture);
- App.ScrollDown("TestCollectionView", ScrollStrategy.Gesture);
- App.ScrollDown("TestCollectionView", ScrollStrategy.Gesture);
-
- // First item should no longer be visible after scrolling
- App.WaitForNoElement("Item 0");
-
- // Tap the status bar area to trigger iOS scroll-to-top
- var rect = App.WaitForElement("TestCollectionView").GetRect();
- App.TapCoordinates(rect.X + (rect.Width / 2), 5);
-
- // Verify first item is visible again after scroll-to-top
- App.WaitForElement("Item 0", timeout: TimeSpan.FromSeconds(5));
- }
-}
-#endif
diff --git a/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue29529.cs b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue29529.cs
deleted file mode 100644
index a1bd51fb3d79..000000000000
--- a/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue29529.cs
+++ /dev/null
@@ -1,28 +0,0 @@
-using NUnit.Framework;
-using UITest.Appium;
-using UITest.Core;
-
-namespace Microsoft.Maui.TestCases.Tests.Issues;
-
-public class Issue29529 : _IssuesUITest
-{
- public override string Issue => "CurrentItemChangedEventArgs and PositionChangedEventArgs Not Updating Correctly in CarouselView";
-
- public Issue29529(TestDevice device)
- : base(device)
- { }
-
- [Test]
- [Category(UITestCategories.CarouselView)]
- public void Issue29529VerifyPreviousPositionOnInsert()
- {
- App.WaitForElement("carouselview");
- App.Tap("InsertButton");
- var text = App.FindElement("positionLabel").GetText();
- Assert.That(text, Is.EqualTo("Current Position: 0, Previous Position: 3"));
- text = App.FindElement("itemLabel").GetText();
- Assert.That(text, Is.EqualTo("Current Item: Item 0, Previous Item: Item 4"));
- text = App.FindElement("eventCountLabel").GetText();
- Assert.That(text, Is.EqualTo("PositionChanged: 1, CurrentItemChanged: 1"));
- }
-}
diff --git a/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue29772.cs b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue29772.cs
deleted file mode 100644
index 39ca543b23c0..000000000000
--- a/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue29772.cs
+++ /dev/null
@@ -1,22 +0,0 @@
-using NUnit.Framework;
-using UITest.Appium;
-using UITest.Core;
-
-namespace Microsoft.Maui.TestCases.Tests.Issues;
-
-public class Issue29772 : _IssuesUITest
-{
- public Issue29772(TestDevice testDevice) : base(testDevice)
- {
- }
-
- public override string Issue => "ItemSpacing doesnot work on CarouselView";
-
- [Test]
- [Category(UITestCategories.CarouselView)]
- public void Issue29772ItemSpaceShouldApply()
- {
- App.WaitForElement("29772DescriptionLabel");
- VerifyScreenshot();
- }
-}
\ No newline at end of file
diff --git a/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue30192.cs b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue30192.cs
deleted file mode 100644
index 4ae29f6d6259..000000000000
--- a/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue30192.cs
+++ /dev/null
@@ -1,24 +0,0 @@
-#if TEST_FAILS_ON_CATALYST && TEST_FAILS_ON_WINDOWS // https://github.com/dotnet/maui/issues/30322
-using NUnit.Framework;
-using UITest.Appium;
-using UITest.Core;
-
-namespace Microsoft.Maui.TestCases.Tests.Issues;
-
-public class Issue30192 : _IssuesUITest
-{
- public Issue30192(TestDevice testDevice) : base(testDevice)
- {
- }
- public override string Issue => "TimePicker FlowDirection Not Working on All Platforms";
-
- [Test]
- [Category(UITestCategories.TimePicker)]
- public void TimePickerFlowDirectionTest()
- {
- App.WaitForElement("ToggleFlowDirectionButton");
- App.Tap("ToggleFlowDirectionButton");
- VerifyScreenshot();
- }
-}
-#endif
\ No newline at end of file
diff --git a/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue30199.cs b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue30199.cs
deleted file mode 100644
index d1281be91cf2..000000000000
--- a/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue30199.cs
+++ /dev/null
@@ -1,25 +0,0 @@
-#if TEST_FAILS_ON_CATALYST //Issue Link https://github.com/dotnet/maui/issues/30532
-using NUnit.Framework;
-using UITest.Appium;
-using UITest.Core;
-
-namespace Microsoft.Maui.TestCases.Tests.Issues;
-
-public class Issue30199 : _IssuesUITest
-{
- public Issue30199(TestDevice device)
- : base(device)
- {
- }
-
- public override string Issue => "TimePicker CharacterSpacing Property Not Working on Windows";
-
- [Test]
- [Category(UITestCategories.TimePicker)]
- public void Issue30199TimePickerCharacterSpacingShouldApply()
- {
- App.WaitForElement("timePicker");
- VerifyScreenshot();
- }
-}
-#endif
\ No newline at end of file
diff --git a/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue30254.cs b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue30254.cs
deleted file mode 100644
index bea9e3bd8709..000000000000
--- a/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue30254.cs
+++ /dev/null
@@ -1,33 +0,0 @@
-using NUnit.Framework;
-using UITest.Appium;
-using UITest.Core;
-
-namespace Microsoft.Maui.TestCases.Tests.Issues;
-
-public class Issue30254 : _IssuesUITest
-{
- public override string Issue => "(Windows) Shell.FlyoutBehavior=Flyout forces the title height space above the tab bar even if the page title is empty";
-
- public Issue30254(TestDevice device) : base(device)
- {
- }
-
- [Test]
- [Category(UITestCategories.Shell)]
- public void ShouldHideHeaderWhenTitleEmpty()
- {
- Exception? exception = null;
-
- App.WaitForElement("GoToWithTitleButton");
- VerifyScreenshotOrSetException(ref exception);
-
- App.Tap("GoToWithTitleButton");
- App.WaitForElement("WithTitleLabel");
- VerifyScreenshotOrSetException(ref exception, "ShouldShowHeaderWhenTitleNotEmpty");
-
- if (exception is not null)
- {
- throw exception;
- }
- }
-}
diff --git a/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue32971.cs b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue32971.cs
deleted file mode 100644
index bd496fea0304..000000000000
--- a/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue32971.cs
+++ /dev/null
@@ -1,25 +0,0 @@
-using NUnit.Framework;
-using UITest.Appium;
-using UITest.Core;
-
-namespace Microsoft.Maui.TestCases.Tests.Issues;
-
-public class Issue32971 : _IssuesUITest
-{
- public override string Issue => "WebView content does not scroll when placed inside a ScrollView";
-
- public Issue32971(TestDevice device) : base(device)
- {
- }
-
- [Test]
- [Category(UITestCategories.WebView)]
- public void WebViewShouldScrollInsideScrollView()
- {
- App.WaitForElement("TestScrollView");
- App.ScrollDown("TestScrollView");
- App.Tap("CheckButton");
- var scrollStateLabel = App.FindElement("ScrollStateLabel").GetText();
- Assert.That(scrollStateLabel, Is.EqualTo("Scrolled"));
- }
-}
\ No newline at end of file
diff --git a/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue33241.cs b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue33241.cs
deleted file mode 100644
index 3015e3a98d6c..000000000000
--- a/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue33241.cs
+++ /dev/null
@@ -1,22 +0,0 @@
-using NUnit.Framework;
-using UITest.Appium;
-using UITest.Core;
-
-namespace Microsoft.Maui.TestCases.Tests.Issues;
-
-public class Issue33241 : _IssuesUITest
-{
- public Issue33241(TestDevice testDevice) : base(testDevice)
- {
- }
-
- public override string Issue => "StackLayout fails to render content while applying Clip, and the layout is placed inside a Border with Background";
-
- [Test]
- [Category(UITestCategories.Border)]
- public void ClippedStackLayoutInsideBorderWithBackgroundRendersCorrectly()
- {
- App.WaitForElement("Label");
- VerifyScreenshot();
- }
-}
diff --git a/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue33783.cs b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue33783.cs
deleted file mode 100644
index d3d51d053727..000000000000
--- a/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue33783.cs
+++ /dev/null
@@ -1,34 +0,0 @@
-using NUnit.Framework;
-using UITest.Appium;
-using UITest.Core;
-
-namespace Microsoft.Maui.TestCases.Tests.Issues;
-
-public class Issue33783 : _IssuesUITest
-{
- public Issue33783(TestDevice testDevice) : base(testDevice)
- {
- }
-
- public override string Issue => "Switch ThumbColor not applied correctly when theme changes on iOS";
-
- [Test, Order(0)]
- [Category(UITestCategories.Switch)]
- public async Task VerifySwitchThumbColorOnDarkThemeChange()
- {
- App.WaitForElement("DarkThemeButton");
- App.Tap("DarkThemeButton");
- await Task.Delay(500);
- VerifyScreenshot("Issue33783_SwitchThumbColor_DarkTheme");
- }
-
- [Test, Order(1)]
- [Category(UITestCategories.Switch)]
- public async Task VerifySwitchThumbColorOnLightThemeChange()
- {
- App.WaitForElement("LightThemeButton");
- App.Tap("LightThemeButton");
- await Task.Delay(500);
- VerifyScreenshot("Issue33783_SwitchThumbColor_LightTheme");
- }
-}
\ No newline at end of file
diff --git a/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue34611.cs b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue34611.cs
deleted file mode 100644
index dedeb2b26977..000000000000
--- a/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue34611.cs
+++ /dev/null
@@ -1,25 +0,0 @@
-using NUnit.Framework;
-using UITest.Appium;
-using UITest.Core;
-
-namespace Microsoft.Maui.TestCases.Tests.Issues;
-
-public class Issue34611 : _IssuesUITest
-{
- public Issue34611(TestDevice device) : base(device)
- {
- }
-
- public override string Issue => "Entry and Editor BackgroundColor not reset to Null";
-
- [Test]
- [Category(UITestCategories.Entry)]
- public void EntryAndEditorBackgroundColorShouldResetToDefaultWhenSetToNull()
- {
- App.WaitForElement("ApplyBackgroundColorButton");
- App.Tap("ApplyBackgroundColorButton");
- App.WaitForElement("TestEntry");
- App.Tap("ResetToDefaultButton");
- VerifyScreenshot();
- }
-}
diff --git a/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue34783.cs b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue34783.cs
deleted file mode 100644
index 706226331b7a..000000000000
--- a/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue34783.cs
+++ /dev/null
@@ -1,54 +0,0 @@
-#if TEST_FAILS_ON_CATALYST && TEST_FAILS_ON_WINDOWS // Android-only fix; exclude MacCatalyst (flaky) and Windows (scroll doesn't recycle items)
-using NUnit.Framework;
-using UITest.Appium;
-using UITest.Core;
-
-namespace Microsoft.Maui.TestCases.Tests.Issues;
-
-public class Issue34783 : _IssuesUITest
-{
- public override string Issue => "CollectionView Dynamic item sizing - After dragging the scrollbar all images return to their original size";
-
- public Issue34783(TestDevice device) : base(device) { }
-
- [Test]
- [Category(UITestCategories.CollectionView)]
- public void ImagesKeepSizeAfterScrolling()
- {
- // Wait for the CollectionView to load; first item "Baboon" image is used as the anchor
- App.WaitForElement("Baboon");
-
- // Record the initial rendered height of the first image (should be ~60)
- var initialRect = App.WaitForElement("Baboon").GetRect();
-
- // Tap the first image to enlarge it (60 → 100) using coordinates to reliably
- // hit the Image element (which has a TapGestureRecognizer, not a Button click)
- App.TapCoordinates(initialRect.X + initialRect.Width / 2, initialRect.Y + initialRect.Height / 2);
-
- // Confirm the image has grown; layout/measure can complete asynchronously after the tap
- App.RetryAssert(() =>
- {
- var enlargedRect = App.WaitForElement("Baboon").GetRect();
- Assert.That(enlargedRect.Height, Is.GreaterThan(initialRect.Height),
- "Image should be enlarged after tap");
- });
-
- // Scroll down to push the first item off screen (simulates dragging the scrollbar,
- // which triggers RecyclerView item recycling on Android)
- App.ScrollDown("Issue34783CollectionView", ScrollStrategy.Gesture, 0.9);
-
- // Verify "Baboon" has left the viewport, confirming RecyclerView recycling will occur
- App.WaitForNoElement("Baboon");
-
- // Scroll back up to bring Baboon back into view
- App.ScrollUp("Issue34783CollectionView", ScrollStrategy.Gesture, 0.9);
- App.ScrollUp("Issue34783CollectionView", ScrollStrategy.Gesture, 0.9);
-
- // Verify the image is still at the enlarged size and was not reset to the original
- App.WaitForElement("Baboon");
- var afterScrollRect = App.WaitForElement("Baboon").GetRect();
- Assert.That(afterScrollRect.Height, Is.GreaterThan(initialRect.Height),
- "Image should keep its enlarged size after scrolling; resetting to original size is the bug");
- }
-}
-#endif
diff --git a/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/CarouselViewShouldRenderCorrectly.png b/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/CarouselViewShouldRenderCorrectly.png
index 99c93d6672d8..ba991729231c 100644
Binary files a/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/CarouselViewShouldRenderCorrectly.png and b/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/CarouselViewShouldRenderCorrectly.png differ
diff --git a/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/ClippedStackLayoutInsideBorderWithBackgroundRendersCorrectly.png b/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/ClippedStackLayoutInsideBorderWithBackgroundRendersCorrectly.png
deleted file mode 100644
index 6d0d0cc1b50e..000000000000
Binary files a/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/ClippedStackLayoutInsideBorderWithBackgroundRendersCorrectly.png and /dev/null differ
diff --git a/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/DefaultSelectedTabTextColorShouldApplyProperly.png b/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/DefaultSelectedTabTextColorShouldApplyProperly.png
index 9b6623d7aafa..a3234088359e 100644
Binary files a/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/DefaultSelectedTabTextColorShouldApplyProperly.png and b/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/DefaultSelectedTabTextColorShouldApplyProperly.png differ
diff --git a/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/DynamicFontImageSourceColorShouldApplyOnTabIcon.png b/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/DynamicFontImageSourceColorShouldApplyOnTabIcon.png
index 621fd7154270..e02d4f1d3237 100644
Binary files a/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/DynamicFontImageSourceColorShouldApplyOnTabIcon.png and b/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/DynamicFontImageSourceColorShouldApplyOnTabIcon.png differ
diff --git a/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/EntryAndEditorBackgroundColorShouldResetToDefaultWhenSetToNull.png b/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/EntryAndEditorBackgroundColorShouldResetToDefaultWhenSetToNull.png
deleted file mode 100644
index e82312e52f2b..000000000000
Binary files a/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/EntryAndEditorBackgroundColorShouldResetToDefaultWhenSetToNull.png and /dev/null differ
diff --git a/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/FontImageSourceColorShouldApplyOnTabIcon.png b/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/FontImageSourceColorShouldApplyOnTabIcon.png
index 2f79554379e0..1c9b3664c1d3 100644
Binary files a/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/FontImageSourceColorShouldApplyOnTabIcon.png and b/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/FontImageSourceColorShouldApplyOnTabIcon.png differ
diff --git a/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/Issue1323Test.png b/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/Issue1323Test.png
index 289f522c6560..a9066e7b2edd 100644
Binary files a/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/Issue1323Test.png and b/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/Issue1323Test.png differ
diff --git a/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/Issue19690_BackToNormalState.png b/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/Issue19690_BackToNormalState.png
deleted file mode 100644
index a73f973df248..000000000000
Binary files a/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/Issue19690_BackToNormalState.png and /dev/null differ
diff --git a/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/Issue19690_CustomState.png b/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/Issue19690_CustomState.png
deleted file mode 100644
index 17fa2fe847a8..000000000000
Binary files a/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/Issue19690_CustomState.png and /dev/null differ
diff --git a/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/Issue19690_InitialNormalState.png b/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/Issue19690_InitialNormalState.png
deleted file mode 100644
index 5e847c5d1410..000000000000
Binary files a/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/Issue19690_InitialNormalState.png and /dev/null differ
diff --git a/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/Issue23834FlyoutMisbehavior.png b/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/Issue23834FlyoutMisbehavior.png
index 1fa007328b87..6d44dab294cf 100644
Binary files a/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/Issue23834FlyoutMisbehavior.png and b/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/Issue23834FlyoutMisbehavior.png differ
diff --git a/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/Issue29772ItemSpaceShouldApply.png b/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/Issue29772ItemSpaceShouldApply.png
deleted file mode 100644
index 1e3fd74dfc41..000000000000
Binary files a/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/Issue29772ItemSpaceShouldApply.png and /dev/null differ
diff --git a/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/Issue30199TimePickerCharacterSpacingShouldApply.png b/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/Issue30199TimePickerCharacterSpacingShouldApply.png
deleted file mode 100644
index 9b2efbc07950..000000000000
Binary files a/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/Issue30199TimePickerCharacterSpacingShouldApply.png and /dev/null differ
diff --git a/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/Issue33783_SwitchThumbColor_DarkTheme.png b/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/Issue33783_SwitchThumbColor_DarkTheme.png
deleted file mode 100644
index f72b69a34e23..000000000000
Binary files a/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/Issue33783_SwitchThumbColor_DarkTheme.png and /dev/null differ
diff --git a/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/Issue33783_SwitchThumbColor_LightTheme.png b/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/Issue33783_SwitchThumbColor_LightTheme.png
deleted file mode 100644
index 88b071a219ad..000000000000
Binary files a/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/Issue33783_SwitchThumbColor_LightTheme.png and /dev/null differ
diff --git a/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/ShellFlowDirectionUpdate.png b/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/ShellFlowDirectionUpdate.png
index 1553bc80cb05..85fb6adce790 100644
Binary files a/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/ShellFlowDirectionUpdate.png and b/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/ShellFlowDirectionUpdate.png differ
diff --git a/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/ShouldHideHeaderWhenTitleEmpty.png b/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/ShouldHideHeaderWhenTitleEmpty.png
deleted file mode 100644
index 322dfcff2aa9..000000000000
Binary files a/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/ShouldHideHeaderWhenTitleEmpty.png and /dev/null differ
diff --git a/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/TabBarIconsShouldAutoscaleTabbedPage.png b/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/TabBarIconsShouldAutoscaleTabbedPage.png
index e66ab26df37b..a3a0e9f1ca6d 100644
Binary files a/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/TabBarIconsShouldAutoscaleTabbedPage.png and b/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/TabBarIconsShouldAutoscaleTabbedPage.png differ
diff --git a/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/VerifyFlyoutBackgroundColor.png b/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/VerifyFlyoutBackgroundColor.png
index b562567ba157..ca9f2ce28223 100644
Binary files a/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/VerifyFlyoutBackgroundColor.png and b/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/VerifyFlyoutBackgroundColor.png differ
diff --git a/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/VerifyFlyoutContentHasNoDefaultCornerRadius.png b/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/VerifyFlyoutContentHasNoDefaultCornerRadius.png
index 21a222d1241d..f5d92f126721 100644
Binary files a/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/VerifyFlyoutContentHasNoDefaultCornerRadius.png and b/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/VerifyFlyoutContentHasNoDefaultCornerRadius.png differ
diff --git a/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/VerifyHamburgerIcon.png b/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/VerifyHamburgerIcon.png
index c53be049a46f..7a0343d5d2da 100644
Binary files a/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/VerifyHamburgerIcon.png and b/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/VerifyHamburgerIcon.png differ
diff --git a/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/VerifyTabbedPageMenuItemTextColor.png b/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/VerifyTabbedPageMenuItemTextColor.png
index f85dda2229dd..9454046076d7 100644
Binary files a/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/VerifyTabbedPageMenuItemTextColor.png and b/src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/VerifyTabbedPageMenuItemTextColor.png differ
diff --git a/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios-26/ClippedStackLayoutInsideBorderWithBackgroundRendersCorrectly.png b/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios-26/ClippedStackLayoutInsideBorderWithBackgroundRendersCorrectly.png
deleted file mode 100644
index f4a3812f20ff..000000000000
Binary files a/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios-26/ClippedStackLayoutInsideBorderWithBackgroundRendersCorrectly.png and /dev/null differ
diff --git a/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios-26/EntryAndEditorBackgroundColorShouldResetToDefaultWhenSetToNull.png b/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios-26/EntryAndEditorBackgroundColorShouldResetToDefaultWhenSetToNull.png
deleted file mode 100644
index 7f25ab9ba4d0..000000000000
Binary files a/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios-26/EntryAndEditorBackgroundColorShouldResetToDefaultWhenSetToNull.png and /dev/null differ
diff --git a/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios-26/Issue19690_BackToNormalState.png b/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios-26/Issue19690_BackToNormalState.png
deleted file mode 100644
index 295268e1f654..000000000000
Binary files a/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios-26/Issue19690_BackToNormalState.png and /dev/null differ
diff --git a/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios-26/Issue19690_CustomState.png b/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios-26/Issue19690_CustomState.png
deleted file mode 100644
index 7ec491ff33e5..000000000000
Binary files a/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios-26/Issue19690_CustomState.png and /dev/null differ
diff --git a/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios-26/Issue19690_InitialNormalState.png b/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios-26/Issue19690_InitialNormalState.png
deleted file mode 100644
index 93f4e856b185..000000000000
Binary files a/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios-26/Issue19690_InitialNormalState.png and /dev/null differ
diff --git a/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios-26/Issue29772ItemSpaceShouldApply.png b/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios-26/Issue29772ItemSpaceShouldApply.png
deleted file mode 100644
index a02bfb6ce6ad..000000000000
Binary files a/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios-26/Issue29772ItemSpaceShouldApply.png and /dev/null differ
diff --git a/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios-26/Issue30199TimePickerCharacterSpacingShouldApply.png b/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios-26/Issue30199TimePickerCharacterSpacingShouldApply.png
deleted file mode 100644
index 6181150dd2bf..000000000000
Binary files a/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios-26/Issue30199TimePickerCharacterSpacingShouldApply.png and /dev/null differ
diff --git a/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios-26/Issue33783_SwitchThumbColor_DarkTheme.png b/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios-26/Issue33783_SwitchThumbColor_DarkTheme.png
deleted file mode 100644
index 54a4bd0ba22e..000000000000
Binary files a/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios-26/Issue33783_SwitchThumbColor_DarkTheme.png and /dev/null differ
diff --git a/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios-26/Issue33783_SwitchThumbColor_LightTheme.png b/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios-26/Issue33783_SwitchThumbColor_LightTheme.png
deleted file mode 100644
index 7919e36ccf31..000000000000
Binary files a/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios-26/Issue33783_SwitchThumbColor_LightTheme.png and /dev/null differ
diff --git a/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios-26/ShouldHideHeaderWhenTitleEmpty.png b/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios-26/ShouldHideHeaderWhenTitleEmpty.png
deleted file mode 100644
index d630048a9c80..000000000000
Binary files a/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios-26/ShouldHideHeaderWhenTitleEmpty.png and /dev/null differ
diff --git a/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios-26/ShouldShowHeaderWhenTitleNotEmpty.png b/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios-26/ShouldShowHeaderWhenTitleNotEmpty.png
deleted file mode 100644
index 1e3d921b2a9f..000000000000
Binary files a/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios-26/ShouldShowHeaderWhenTitleNotEmpty.png and /dev/null differ
diff --git a/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios-26/TimePickerFlowDirectionTest.png b/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios-26/TimePickerFlowDirectionTest.png
deleted file mode 100644
index e1159fa6e5ee..000000000000
Binary files a/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios-26/TimePickerFlowDirectionTest.png and /dev/null differ
diff --git a/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/ClippedStackLayoutInsideBorderWithBackgroundRendersCorrectly.png b/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/ClippedStackLayoutInsideBorderWithBackgroundRendersCorrectly.png
deleted file mode 100644
index efab4306bb81..000000000000
Binary files a/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/ClippedStackLayoutInsideBorderWithBackgroundRendersCorrectly.png and /dev/null differ
diff --git a/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/EntryAndEditorBackgroundColorShouldResetToDefaultWhenSetToNull.png b/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/EntryAndEditorBackgroundColorShouldResetToDefaultWhenSetToNull.png
deleted file mode 100644
index 3bd55f5c93bb..000000000000
Binary files a/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/EntryAndEditorBackgroundColorShouldResetToDefaultWhenSetToNull.png and /dev/null differ
diff --git a/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/Issue19690_BackToNormalState.png b/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/Issue19690_BackToNormalState.png
deleted file mode 100644
index 1bda06364608..000000000000
Binary files a/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/Issue19690_BackToNormalState.png and /dev/null differ
diff --git a/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/Issue19690_CustomState.png b/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/Issue19690_CustomState.png
deleted file mode 100644
index 0c3369f564d2..000000000000
Binary files a/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/Issue19690_CustomState.png and /dev/null differ
diff --git a/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/Issue19690_InitialNormalState.png b/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/Issue19690_InitialNormalState.png
deleted file mode 100644
index c75c17b403e6..000000000000
Binary files a/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/Issue19690_InitialNormalState.png and /dev/null differ
diff --git a/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/Issue29772ItemSpaceShouldApply.png b/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/Issue29772ItemSpaceShouldApply.png
deleted file mode 100644
index 9abdad597f3f..000000000000
Binary files a/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/Issue29772ItemSpaceShouldApply.png and /dev/null differ
diff --git a/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/Issue30199TimePickerCharacterSpacingShouldApply.png b/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/Issue30199TimePickerCharacterSpacingShouldApply.png
deleted file mode 100644
index 6181150dd2bf..000000000000
Binary files a/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/Issue30199TimePickerCharacterSpacingShouldApply.png and /dev/null differ
diff --git a/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/Issue33783_SwitchThumbColor_DarkTheme.png b/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/Issue33783_SwitchThumbColor_DarkTheme.png
deleted file mode 100644
index 01d7fc5f105c..000000000000
Binary files a/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/Issue33783_SwitchThumbColor_DarkTheme.png and /dev/null differ
diff --git a/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/Issue33783_SwitchThumbColor_LightTheme.png b/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/Issue33783_SwitchThumbColor_LightTheme.png
deleted file mode 100644
index 588f11fc21ff..000000000000
Binary files a/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/Issue33783_SwitchThumbColor_LightTheme.png and /dev/null differ
diff --git a/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/ShouldHideHeaderWhenTitleEmpty.png b/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/ShouldHideHeaderWhenTitleEmpty.png
deleted file mode 100644
index 04757a6499f9..000000000000
Binary files a/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/ShouldHideHeaderWhenTitleEmpty.png and /dev/null differ
diff --git a/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/ShouldShowHeaderWhenTitleNotEmpty.png b/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/ShouldShowHeaderWhenTitleNotEmpty.png
deleted file mode 100644
index 83744eb56418..000000000000
Binary files a/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/ShouldShowHeaderWhenTitleNotEmpty.png and /dev/null differ
diff --git a/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/TimePickerFlowDirectionTest.png b/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/TimePickerFlowDirectionTest.png
deleted file mode 100644
index 23b450de6b13..000000000000
Binary files a/src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/TimePickerFlowDirectionTest.png and /dev/null differ
diff --git a/src/Controls/tests/Xaml.UnitTests/Issues/Maui34712.sgen.xaml b/src/Controls/tests/Xaml.UnitTests/Issues/Maui34712.sgen.xaml
deleted file mode 100644
index 55b59b09dfe5..000000000000
--- a/src/Controls/tests/Xaml.UnitTests/Issues/Maui34712.sgen.xaml
+++ /dev/null
@@ -1,15 +0,0 @@
-
-
- "Hello from x:Code";
-
- public string GetFormattedDate()
- => DateTime.Now.ToString("d", CultureInfo.InvariantCulture);
- ]]>
-
-
diff --git a/src/Controls/tests/Xaml.UnitTests/Issues/Maui34712.xaml.cs b/src/Controls/tests/Xaml.UnitTests/Issues/Maui34712.xaml.cs
deleted file mode 100644
index d34f85b79f0c..000000000000
--- a/src/Controls/tests/Xaml.UnitTests/Issues/Maui34712.xaml.cs
+++ /dev/null
@@ -1,78 +0,0 @@
-using System;
-using System.Linq;
-using Microsoft.Maui.Controls.Build.Tasks;
-using Xunit;
-
-using static Microsoft.Maui.Controls.Xaml.UnitTests.MockSourceGenerator;
-
-namespace Microsoft.Maui.Controls.Xaml.UnitTests;
-
-public partial class Maui34712 : ContentPage
-{
- public Maui34712() => InitializeComponent();
-
- [Collection("Issue")]
- public class Tests
- {
- [Fact]
- public void XCodeSucceedsWithSourceGen()
- {
- var page = new Maui34712(XamlInflator.SourceGen);
- Assert.NotNull(page);
- Assert.Equal("Hello from x:Code", page.GetMessage());
- // Verify that using System.Globalization was promoted correctly
- Assert.NotNull(page.GetFormattedDate());
- }
-
- [Fact]
- public void XCodeFailsAtRuntime()
- {
- // x:Code requires SourceGen; runtime inflation is not supported
- Assert.Throws(() => new Maui34712(XamlInflator.Runtime));
- }
-
- [Fact]
- public void XCodeFailsWithXamlC()
- {
- // x:Code requires SourceGen; XamlC compilation is not supported
- Assert.Throws(() => new Maui34712(XamlInflator.XamlC));
- }
-
- [Fact]
- public void XCodeSourceGenProducesNoDiagnostics()
- {
- var result = CreateMauiCompilation()
- .WithAdditionalSource(
-"""
-namespace Microsoft.Maui.Controls.Xaml.UnitTests;
-
-[XamlProcessing(XamlInflator.SourceGen)]
-public partial class Maui34712 : ContentPage
-{
- public Maui34712() => InitializeComponent();
-}
-""")
- .RunMauiSourceGenerator(
- new AdditionalXamlFile(
- "Issues/Maui34712.sgen.xaml",
-"""
-
-
- "Hello from x:Code";
-
- public string GetFormattedDate()
- => DateTime.Now.ToString("d", CultureInfo.InvariantCulture);
- ]]>
-
-
-"""));
- Assert.Empty(result.Diagnostics);
- }
- }
-}
diff --git a/src/Core/maps/src/Handlers/Map/MapHandler.Android.cs b/src/Core/maps/src/Handlers/Map/MapHandler.Android.cs
index 30815748619e..3deb4d4c5001 100644
--- a/src/Core/maps/src/Handlers/Map/MapHandler.Android.cs
+++ b/src/Core/maps/src/Handlers/Map/MapHandler.Android.cs
@@ -1,7 +1,6 @@
using System;
using System.Collections;
using System.Collections.Generic;
-using System.ComponentModel;
using System.Linq;
using System.Threading.Tasks;
using Android.Gms.Common.Apis;
@@ -57,8 +56,6 @@ protected override void ConnectHandler(MapView platformView)
protected override void DisconnectHandler(MapView platformView)
{
- DisconnectPins();
-
base.DisconnectHandler(platformView);
platformView.LayoutChange -= MapViewLayoutChange;
@@ -276,14 +273,10 @@ public static void MapPins(IMapHandler handler, IMap map)
{
if (handler is MapHandler mapHandler)
{
- mapHandler.DisconnectPins();
-
if (mapHandler._markers != null)
{
for (int i = 0; i < mapHandler._markers.Count; i++)
- {
mapHandler._markers[i].Remove();
- }
mapHandler._markers = null;
}
@@ -457,7 +450,8 @@ void AddPins(IList pins)
if (Map == null || MauiContext == null)
return;
- _markers ??= new List();
+ if (_markers == null)
+ _markers = new List();
foreach (var p in pins)
{
@@ -467,79 +461,20 @@ void AddPins(IList pins)
var pinHandler = pin.ToHandler(MauiContext);
if (pinHandler is IMapPinHandler iMapPinHandler)
{
- marker = Map.AddMarker(iMapPinHandler.PlatformView) ?? throw new System.Exception("Map.AddMarker returned null");
+ marker = Map.AddMarker(iMapPinHandler.PlatformView);
+ if (marker == null)
+ {
+ throw new System.Exception("Map.AddMarker returned null");
+ }
// associate pin with marker for later lookup in event handlers
pin.MarkerId = marker.Id;
_markers.Add(marker!);
}
- if (pin is INotifyPropertyChanged observable)
- {
- observable.PropertyChanged += PinOnPropertyChanged;
- }
}
_pins = null;
}
- void PinOnPropertyChanged(object? sender, PropertyChangedEventArgs e)
- {
- if (sender is not IMapPin pin || _markers == null)
- {
- return;
- }
-
- Marker? marker = null;
- if (pin.MarkerId is string markerId)
- {
- for (int i = 0; i < _markers.Count; i++)
- {
- if (_markers[i].Id == markerId)
- {
- marker = _markers[i];
- break;
- }
- }
- }
-
- if (marker is null)
- {
- return;
- }
-
- switch (e.PropertyName)
- {
- case nameof(IMapPin.Location):
- if (pin.Location != null)
- {
- marker.Position = new LatLng(pin.Location.Latitude, pin.Location.Longitude);
- }
-
- break;
- case nameof(IMapPin.Label):
- marker.Title = pin.Label;
- break;
- case nameof(IMapPin.Address):
- marker.Snippet = pin.Address;
- break;
- }
- }
-
- void DisconnectPins()
- {
- if (VirtualView == null)
- return;
-
- for (int i = 0; i < VirtualView.Pins.Count; i++)
- {
- var pin = VirtualView.Pins[i];
- if (pin is INotifyPropertyChanged observable)
- {
- observable.PropertyChanged -= PinOnPropertyChanged;
- }
- pin?.Handler?.DisconnectHandler();
- }
- }
-
protected IMapPin? GetPinForMarker(Marker marker)
{
IMapPin? targetPin = null;
@@ -786,4 +721,4 @@ protected override void Dispose(bool disposing)
}
}
-}
\ No newline at end of file
+}
diff --git a/src/Core/maps/src/Handlers/MapPin/MapPinHandler.Android.cs b/src/Core/maps/src/Handlers/MapPin/MapPinHandler.Android.cs
index da48dbf2092c..b02d5020e563 100644
--- a/src/Core/maps/src/Handlers/MapPin/MapPinHandler.Android.cs
+++ b/src/Core/maps/src/Handlers/MapPin/MapPinHandler.Android.cs
@@ -1,4 +1,4 @@
-using Android.Gms.Maps;
+using Android.Gms.Maps;
using Android.Gms.Maps.Model;
using Microsoft.Maui.Handlers;
@@ -10,10 +10,8 @@ public partial class MapPinHandler : ElementHandler
public static void MapLocation(IMapPinHandler handler, IMapPin mapPin)
{
- if (mapPin.Location is not null)
- {
+ if (mapPin.Location != null)
handler.PlatformView.SetPosition(new LatLng(mapPin.Location.Latitude, mapPin.Location.Longitude));
- }
}
public static void MapLabel(IMapPinHandler handler, IMapPin mapPin)
diff --git a/src/Core/maps/src/PublicAPI/net-android/PublicAPI.Unshipped.txt b/src/Core/maps/src/PublicAPI/net-android/PublicAPI.Unshipped.txt
index ab058de62d44..7dc5c58110bf 100644
--- a/src/Core/maps/src/PublicAPI/net-android/PublicAPI.Unshipped.txt
+++ b/src/Core/maps/src/PublicAPI/net-android/PublicAPI.Unshipped.txt
@@ -1 +1 @@
-#nullable enable
+#nullable enable
diff --git a/src/Core/src/Handlers/Button/ButtonHandler.Android.cs b/src/Core/src/Handlers/Button/ButtonHandler.Android.cs
index 9c38bba095c6..32d77810e857 100644
--- a/src/Core/src/Handlers/Button/ButtonHandler.Android.cs
+++ b/src/Core/src/Handlers/Button/ButtonHandler.Android.cs
@@ -23,10 +23,6 @@ public partial class ButtonHandler : ViewHandler
ButtonClickListener ClickListener { get; } = new ButtonClickListener();
ButtonTouchListener TouchListener { get; } = new ButtonTouchListener();
- // Cached default Material theme text colors, captured before any MAUI property mapping.
- // Restored when TextColor is set to null (e.g. when a VisualState setter is unapplied).
- ColorStateList? _defaultTextColors;
-
protected override MaterialButton CreatePlatformView()
{
MaterialButton platformButton = new MauiMaterialButton(Context)
@@ -51,9 +47,6 @@ protected override void ConnectHandler(MaterialButton platformView)
platformView.FocusChange += OnNativeViewFocusChange;
platformView.LayoutChange += OnPlatformViewLayoutChange;
- // Capture Material theme defaults before MAUI property mapping is applied
- _defaultTextColors = platformView.TextColors;
-
base.ConnectHandler(platformView);
}
@@ -68,8 +61,6 @@ protected override void DisconnectHandler(MaterialButton platformView)
platformView.FocusChange -= OnNativeViewFocusChange;
platformView.LayoutChange -= OnPlatformViewLayoutChange;
- _defaultTextColors = null;
-
ImageSourceLoader.Reset();
base.DisconnectHandler(platformView);
@@ -108,16 +99,7 @@ public static void MapText(IButtonHandler handler, IText button)
public static void MapTextColor(IButtonHandler handler, ITextStyle button)
{
- if (button.TextColor is null)
- {
- // Restore the Material theme default colors captured before any MAUI mapping
- if (handler is ButtonHandler buttonHandler && buttonHandler._defaultTextColors is not null)
- handler.PlatformView?.SetTextColor(buttonHandler._defaultTextColors);
- }
- else
- {
- handler.PlatformView?.UpdateTextColor(button);
- }
+ handler.PlatformView?.UpdateTextColor(button);
}
public static void MapCharacterSpacing(IButtonHandler handler, ITextStyle button)
diff --git a/src/Core/src/Handlers/Button/ButtonHandler.iOS.cs b/src/Core/src/Handlers/Button/ButtonHandler.iOS.cs
index 678e953c4acc..67857555be26 100644
--- a/src/Core/src/Handlers/Button/ButtonHandler.iOS.cs
+++ b/src/Core/src/Handlers/Button/ButtonHandler.iOS.cs
@@ -73,15 +73,9 @@ public static void MapBackground(IButtonHandler handler, IButton button)
}
else
{
- handler.PlatformView?.UpdateBackground(button.Background);
+ handler.PlatformView?.UpdateBackground(button);
}
}
-#else
- // TODO: Make this public in .NET 11
- internal static void MapBackground(IButtonHandler handler, IButton button)
- {
- handler.PlatformView?.UpdateBackground(button.Background);
- }
#endif
public static void MapStrokeColor(IButtonHandler handler, IButtonStroke buttonStroke)
diff --git a/src/Core/src/Handlers/Editor/EditorHandler.iOS.cs b/src/Core/src/Handlers/Editor/EditorHandler.iOS.cs
index 7ce02ec4ed6b..aaf1a2ec7eda 100644
--- a/src/Core/src/Handlers/Editor/EditorHandler.iOS.cs
+++ b/src/Core/src/Handlers/Editor/EditorHandler.iOS.cs
@@ -84,28 +84,6 @@ public static void MapText(IEditorHandler handler, IEditor editor)
MapFormatting(handler, editor);
}
- public static void MapBackground(IEditorHandler handler, IEditor editor)
- {
- if (handler.PlatformView is not MauiTextView platformView)
- return;
-
- if (editor.Background is ImageSourcePaint image)
- {
- var provider = handler.GetRequiredService();
- platformView.UpdateBackgroundImageSourceAsync(image.ImageSource, provider)
- .FireAndForget(handler);
- }
- else if (editor.Background.IsNullOrEmpty())
- {
- platformView.RemoveBackgroundLayer();
- platformView.BackgroundColor = null;
- }
- else
- {
- platformView.UpdateBackground(editor);
- }
- }
-
public static void MapTextColor(IEditorHandler handler, IEditor editor) =>
handler.PlatformView?.UpdateTextColor(editor);
diff --git a/src/Core/src/Handlers/Entry/EntryHandler.iOS.cs b/src/Core/src/Handlers/Entry/EntryHandler.iOS.cs
index ec5779150915..728499247c66 100644
--- a/src/Core/src/Handlers/Entry/EntryHandler.iOS.cs
+++ b/src/Core/src/Handlers/Entry/EntryHandler.iOS.cs
@@ -48,30 +48,6 @@ public static void MapText(IEntryHandler handler, IEntry entry)
MapFormatting(handler, entry);
}
- public static void MapBackground(IEntryHandler handler, IEntry entry)
- {
- if (handler.PlatformView is not MauiTextField platformView)
- return;
-
- if (entry.Background is ImageSourcePaint image)
- {
- var provider = handler.GetRequiredService();
- platformView.UpdateBackgroundImageSourceAsync(image.ImageSource, provider)
- .FireAndForget(handler);
- return;
- }
- else if (entry.Background.IsNullOrEmpty())
- {
- platformView.RemoveBackgroundLayer();
- platformView.BackgroundColor = null;
- return;
- }
- else
- {
- platformView.UpdateBackground(entry);
- }
- }
-
public static void MapTextColor(IEntryHandler handler, IEntry entry)
{
handler.PlatformView?.UpdateTextColor(entry);
@@ -236,8 +212,8 @@ void OnEditingChanged(object? sender, EventArgs e)
VirtualView.UpdateText(platformView.Text);
}
- }
-
+ }
+
void OnEditingEnded(object? sender, EventArgs e)
{
if (sender is MauiTextField platformView && VirtualView is IEntry virtualView)
diff --git a/src/Core/src/Handlers/HybridWebView/HybridWebViewHandler.Standard.cs b/src/Core/src/Handlers/HybridWebView/HybridWebViewHandler.Standard.cs
index 862117e34d24..876cb0f223f1 100644
--- a/src/Core/src/Handlers/HybridWebView/HybridWebViewHandler.Standard.cs
+++ b/src/Core/src/Handlers/HybridWebView/HybridWebViewHandler.Standard.cs
@@ -8,8 +8,6 @@ public partial class HybridWebViewHandler : ViewHandler
public static void MapEvaluateJavaScriptAsync(IHybridWebViewHandler handler, IHybridWebView hybridWebView, object? arg) { }
- public static void MapInvokeJavaScriptAsync(IHybridWebViewHandler handler, IHybridWebView hybridWebView, object? arg) { }
-
public static void MapSendRawMessage(IHybridWebViewHandler handler, IHybridWebView hybridWebView, object? arg) { }
}
}
\ No newline at end of file
diff --git a/src/Core/src/Handlers/HybridWebView/HybridWebViewHandler.Tizen.cs b/src/Core/src/Handlers/HybridWebView/HybridWebViewHandler.Tizen.cs
index 14330d546594..c686585c373e 100644
--- a/src/Core/src/Handlers/HybridWebView/HybridWebViewHandler.Tizen.cs
+++ b/src/Core/src/Handlers/HybridWebView/HybridWebViewHandler.Tizen.cs
@@ -8,8 +8,6 @@ public partial class HybridWebViewHandler : ViewHandler
!AppContext.TryGetSwitch(InvokeJavaScriptThrowsExceptionsSwitch, out var enabled) || enabled;
-#if PLATFORM && !TIZEN
- void MessageReceived(string rawMessage) =>
- HybridWebViewHelper.ProcessRawMessage(this, VirtualView, rawMessage);
+ void MessageReceived(string rawMessage)
+ {
+ if (string.IsNullOrEmpty(rawMessage))
+ {
+ throw new ArgumentException($"The raw message cannot be null or empty.", nameof(rawMessage));
+ }
+#if !NETSTANDARD2_0
+ var indexOfPipe = rawMessage.IndexOf('|', StringComparison.Ordinal);
+#else
+ var indexOfPipe = rawMessage.IndexOf("|", StringComparison.Ordinal);
+#endif
+ if (indexOfPipe == -1)
+ {
+ throw new ArgumentException($"The raw message must contain a pipe character ('|').", nameof(rawMessage));
+ }
+
+ var messageType = rawMessage.Substring(0, indexOfPipe);
+ var messageContent = rawMessage.Substring(indexOfPipe + 1);
+
+ switch (messageType)
+ {
+ case "__InvokeJavaScriptFailed":
+ case "__InvokeJavaScriptCompleted":
+ {
+#if !NETSTANDARD2_0
+ var indexOfPipeInContent = messageContent.IndexOf('|', StringComparison.Ordinal);
+#else
+ var indexOfPipeInContent = messageContent.IndexOf("|", StringComparison.Ordinal);
+#endif
+ if (indexOfPipeInContent == -1)
+ {
+ throw new ArgumentException($"The '{messageType}' message content must contain a pipe character ('|').", nameof(rawMessage));
+ }
+
+ var taskId = messageContent.Substring(0, indexOfPipeInContent);
+ var result = messageContent.Substring(indexOfPipeInContent + 1);
+
+ var taskManager = this.GetRequiredService();
+ if (messageType == "__InvokeJavaScriptFailed")
+ {
+ if (IsInvokeJavaScriptThrowsExceptionsEnabled)
+ {
+ if (string.IsNullOrWhiteSpace(result))
+ {
+ taskManager.SetTaskFailed(taskId, new HybridWebViewInvokeJavaScriptException());
+ }
+ else
+ {
+ var jsError = JsonSerializer.Deserialize(result, HybridWebViewHandlerJsonContext.Default.JSInvokeError);
+ var jsException = new HybridWebViewInvokeJavaScriptException(jsError?.Message, jsError?.Name, jsError?.StackTrace);
+ var ex = new HybridWebViewInvokeJavaScriptException($"InvokeJavaScript threw an exception: {jsException.Message}", jsException);
+ taskManager.SetTaskFailed(taskId, ex);
+ }
+ }
+ }
+ else
+ {
+ taskManager.SetTaskCompleted(taskId, result);
+ }
+ }
+ break;
+ case "__RawMessage":
+ VirtualView?.RawMessageReceived(messageContent);
+ break;
+ default:
+ throw new ArgumentException($"The message type '{messageType}' is not recognized.", nameof(rawMessage));
+ }
+ }
internal async Task InvokeDotNetAsync(Stream? streamBody = null, string? stringBody = null)
{
- var logger = MauiContext?.CreateLogger();
- return await HybridWebViewHelper.ProcessInvokeDotNetAsync(
- VirtualView?.InvokeJavaScriptTarget,
- VirtualView?.InvokeJavaScriptType,
- logger,
- streamBody,
- stringBody);
+ try
+ {
+ var invokeTarget = VirtualView.InvokeJavaScriptTarget ?? throw new InvalidOperationException($"The {nameof(IHybridWebView)}.{nameof(IHybridWebView.InvokeJavaScriptTarget)} property must have a value in order to invoke a .NET method from JavaScript.");
+ var invokeTargetType = VirtualView.InvokeJavaScriptType ?? throw new InvalidOperationException($"The {nameof(IHybridWebView)}.{nameof(IHybridWebView.InvokeJavaScriptType)} property must have a value in order to invoke a .NET method from JavaScript.");
+
+ JSInvokeMethodData? invokeData = null;
+ if (streamBody is not null)
+ {
+ invokeData = await JsonSerializer.DeserializeAsync(streamBody, HybridWebViewHandlerJsonContext.Default.JSInvokeMethodData);
+ }
+ else if (stringBody is not null && !string.IsNullOrWhiteSpace(stringBody))
+ {
+ invokeData = JsonSerializer.Deserialize(stringBody, HybridWebViewHandlerJsonContext.Default.JSInvokeMethodData);
+ }
+
+ if (invokeData?.MethodName is null)
+ {
+ throw new InvalidOperationException("The invoke data did not provide a method name.");
+ }
+
+ var invokeResultRaw = await InvokeDotNetMethodAsync(invokeTargetType, invokeTarget, invokeData);
+ var invokeResult = CreateInvokeResult(invokeResultRaw);
+ var json = JsonSerializer.Serialize(invokeResult);
+ var contentBytes = Encoding.UTF8.GetBytes(json);
+
+ return contentBytes;
+ }
+ catch (Exception ex)
+ {
+ MauiContext?.CreateLogger()?.LogError(ex, "An error occurred while invoking a .NET method from JavaScript: {ErrorMessage}", ex.Message);
+
+ // Return error response instead of null so JavaScript can handle the error
+ var errorResult = CreateErrorResult(ex);
+ var errorJson = JsonSerializer.Serialize(errorResult, HybridWebViewHandlerJsonContext.Default.DotNetInvokeResult);
+ var errorBytes = Encoding.UTF8.GetBytes(errorJson);
+ return errorBytes;
+ }
}
-#endif
+ private static DotNetInvokeResult CreateInvokeResult(object? result)
+ {
+ // null invoke result means an empty result
+ if (result is null)
+ {
+ return new();
+ }
+
+ // a reference type or an array should be serialized to JSON
+ var resultType = result.GetType();
+ if (resultType.IsArray || resultType.IsClass)
+ {
+ return new DotNetInvokeResult()
+ {
+ Result = JsonSerializer.Serialize(result),
+ IsJson = true,
+ };
+ }
+
+ // a value type should be returned as is
+ return new DotNetInvokeResult()
+ {
+ Result = result,
+ };
+ }
+
+ private static DotNetInvokeResult CreateErrorResult(Exception ex)
+ {
+ return new DotNetInvokeResult()
+ {
+ IsError = true,
+ ErrorMessage = ex.Message,
+ ErrorType = ex.GetType().Name,
+ ErrorStackTrace = ex.StackTrace
+ };
+ }
+
+ private static async Task InvokeDotNetMethodAsync(
+ [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] Type targetType,
+ object jsInvokeTarget,
+ JSInvokeMethodData invokeData)
+ {
+ var requestMethodName = invokeData.MethodName!;
+ var requestParams = invokeData.ParamValues;
+
+ // get the method and its parameters from the .NET object instance
+ var dotnetMethod = targetType.GetMethod(requestMethodName, BindingFlags.Public | BindingFlags.Instance | BindingFlags.InvokeMethod);
+ if (dotnetMethod is null)
+ {
+ throw new InvalidOperationException($"The method {requestMethodName} couldn't be found on the {nameof(jsInvokeTarget)} of type {jsInvokeTarget.GetType().FullName}.");
+ }
+ var dotnetParams = dotnetMethod.GetParameters();
+ if (requestParams is not null && dotnetParams.Length != requestParams.Length)
+ {
+ throw new InvalidOperationException($"The number of parameters on {nameof(jsInvokeTarget)}'s method {requestMethodName} ({dotnetParams.Length}) doesn't match the number of values passed from JavaScript code ({requestParams.Length}).");
+ }
+
+ // deserialize the parameters from JSON to .NET types
+ object?[]? invokeParamValues = null;
+ if (requestParams is not null)
+ {
+ invokeParamValues = new object?[requestParams.Length];
+ for (var i = 0; i < requestParams.Length; i++)
+ {
+ var reqValue = requestParams[i];
+ var paramType = dotnetParams[i].ParameterType;
+ var deserialized = JsonSerializer.Deserialize(reqValue, paramType);
+ invokeParamValues[i] = deserialized;
+ }
+ }
+
+ // invoke the .NET method
+ var dotnetReturnValue = GetDotNetMethodReturnValue(jsInvokeTarget, dotnetMethod, invokeParamValues);
+
+ if (dotnetReturnValue is null) // null result
+ {
+ return null;
+ }
+
+ if (dotnetReturnValue is Task task) // Task or Task result
+ {
+ await task;
+
+ // Task
+ if (dotnetMethod.ReturnType.IsGenericType)
+ {
+ var resultProperty = dotnetMethod.ReturnType.GetProperty(nameof(Task.Result));
+ return resultProperty?.GetValue(task);
+ }
+
+ // Task
+ return null;
+ }
+
+ return dotnetReturnValue; // regular result
+ }
+
+ private static object? GetDotNetMethodReturnValue(object jsInvokeTarget, MethodInfo dotnetMethod, object?[]? invokeParamValues)
+ {
+ try
+ {
+ // invoke the .NET method
+ return dotnetMethod.Invoke(jsInvokeTarget, invokeParamValues);
+ }
+ catch (TargetInvocationException tie) // unwrap while preserving original stack trace
+ {
+ if (tie.InnerException is not null)
+ {
+ // Rethrow the underlying exception without losing its original stack trace
+ ExceptionDispatchInfo.Capture(tie.InnerException).Throw();
+
+ // unreachable, but required for compiler flow analysis
+ throw;
+ }
+
+ // no inner exception; rethrow the TargetInvocationException itself preserving its stack
+ throw;
+ }
+ }
+
+ private sealed class JSInvokeMethodData
+ {
+ public string? MethodName { get; set; }
+ public string[]? ParamValues { get; set; }
+ }
+
+ private sealed class JSInvokeError
+ {
+ public string? Name { get; set; }
+ public string? Message { get; set; }
+ public string? StackTrace { get; set; }
+ }
+
+ private sealed class DotNetInvokeResult
+ {
+ public object? Result { get; set; }
+ public bool IsJson { get; set; }
+ public bool IsError { get; set; }
+ public string? ErrorMessage { get; set; }
+ public string? ErrorType { get; set; }
+ public string? ErrorStackTrace { get; set; }
+ }
+
+ [JsonSourceGenerationOptions()]
+ [JsonSerializable(typeof(JSInvokeMethodData))]
+ [JsonSerializable(typeof(JSInvokeError))]
+ [JsonSerializable(typeof(DotNetInvokeResult))]
+ private partial class HybridWebViewHandlerJsonContext : JsonSerializerContext
+ {
+ }
+
+
#if PLATFORM && !TIZEN
public static async void MapEvaluateJavaScriptAsync(IHybridWebViewHandler handler, IHybridWebView hybridWebView, object? arg)
{
- if (arg is not EvaluateJavaScriptAsyncRequest request)
+ if (arg is not EvaluateJavaScriptAsyncRequest request ||
+ handler.PlatformView is not MauiHybridWebView hybridPlatformWebView)
{
return;
}
@@ -135,45 +393,118 @@ public static async void MapEvaluateJavaScriptAsync(IHybridWebViewHandler handle
return;
}
- try
+ var script = request.Script;
+ // Make all the platforms mimic Android's implementation, which is by far the most complete.
+ if (!OperatingSystem.IsAndroid())
{
- // Delegate to helper for all processing logic
- var result = await HybridWebViewHelper.ProcessEvaluateJavaScriptAsync(handler, hybridWebView, request);
+ script = WebViewHelper.EscapeJsString(script);
+
+ if (!OperatingSystem.IsWindows())
+ {
+ // Use JSON.stringify() method to converts a JavaScript value to a JSON string
+ script = "try{JSON.stringify(eval('" + script + "'))}catch(e){'null'};";
+ }
+ else
+ {
+ script = "try{eval('" + script + "')}catch(e){'null'};";
+ }
+ }
+
+ // Use the handler command to evaluate the JS
+ var innerRequest = new EvaluateJavaScriptAsyncRequest(script);
+ EvaluateJavaScript(handler, hybridWebView, innerRequest);
+
+ var result = await innerRequest.Task;
- request.SetResult(result!);
+ //if the js function errored or returned null/undefined treat it as null
+ if (result == "null")
+ {
+ result = null;
}
- catch (Exception ex)
+ //JSON.stringify wraps the result in literal quotes, we just want the actual returned result
+ //note that if the js function returns the string "null" we will get here and not above
+ else if (result != null)
{
- request.SetException(ex);
+ result = result.Trim('"');
}
+
+ request.SetResult(result!);
+
}
+#endif
public static async void MapInvokeJavaScriptAsync(IHybridWebViewHandler handler, IHybridWebView hybridWebView, object? arg)
{
- if (arg is not HybridWebViewInvokeJavaScriptRequest request)
- {
- return;
- }
-
- if (handler.PlatformView is null)
+#if PLATFORM && !TIZEN
+ if (arg is not HybridWebViewInvokeJavaScriptRequest invokeJavaScriptRequest)
{
- request.SetCanceled();
return;
}
try
{
- // Delegate to helper for all processing logic
- var result = await HybridWebViewHelper.ProcessInvokeJavaScriptAsync(handler, hybridWebView, request);
+ var result = await MapInvokeJavaScriptAsyncImpl(handler, hybridWebView, invokeJavaScriptRequest);
- request.SetResult(result);
+ invokeJavaScriptRequest.SetResult(result);
}
catch (Exception ex)
{
- request.SetException(ex);
+ invokeJavaScriptRequest.SetException(ex);
}
- }
+#else
+ await Task.CompletedTask;
#endif
+ }
+
+ static async Task MapInvokeJavaScriptAsyncImpl(IHybridWebViewHandler handler, IHybridWebView hybridWebView, HybridWebViewInvokeJavaScriptRequest invokeJavaScriptRequest)
+ {
+ // Create a callback for async JavaScript methods to invoke when they are done
+ var taskManager = handler.GetRequiredService();
+ var (currentInvokeTaskId, callback) = taskManager.CreateTask();
+
+ var paramsValuesStringArray =
+ invokeJavaScriptRequest.ParamValues == null
+ ? string.Empty
+ : string.Join(
+ ", ",
+ invokeJavaScriptRequest.ParamValues.Select((v, i) => (v == null ? "null" : JsonSerializer.Serialize(v, invokeJavaScriptRequest.ParamJsonTypeInfos![i]!))));
+
+ await handler.InvokeAsync(nameof(IHybridWebView.EvaluateJavaScriptAsync),
+ new EvaluateJavaScriptAsyncRequest($"window.HybridWebView.__InvokeJavaScript({currentInvokeTaskId}, {invokeJavaScriptRequest.MethodName}, [{paramsValuesStringArray}])"));
+
+ var stringResult = await callback.Task;
+
+ // if there is no result or if the result was null/undefined, then treat it as null
+ if (stringResult is null || stringResult == "null" || stringResult == "undefined")
+ {
+ return null;
+ }
+ // if we are not looking for a return object, then return null
+ else if (invokeJavaScriptRequest.ReturnTypeJsonTypeInfo is null)
+ {
+ return null;
+ }
+ // if we are expecting a result, then deserialize what we have
+ else
+ {
+ var typedResult = JsonSerializer.Deserialize(stringResult, invokeJavaScriptRequest.ReturnTypeJsonTypeInfo);
+ return typedResult;
+ }
+ }
+
+ internal static async Task GetAssetContentAsync(string assetPath)
+ {
+ using var stream = await GetAssetStreamAsync(assetPath);
+ if (stream == null)
+ {
+ return null;
+ }
+ using var reader = new StreamReader(stream);
+
+ var contents = reader.ReadToEnd();
+
+ return contents;
+ }
internal static async Task GetAssetStreamAsync(string assetPath)
{
diff --git a/src/Core/src/Handlers/HybridWebView/HybridWebViewHelper.cs b/src/Core/src/Handlers/HybridWebView/HybridWebViewHelper.cs
deleted file mode 100644
index 65b82df20bf9..000000000000
--- a/src/Core/src/Handlers/HybridWebView/HybridWebViewHelper.cs
+++ /dev/null
@@ -1,482 +0,0 @@
-#if PLATFORM && !TIZEN
-using System;
-using System.Diagnostics.CodeAnalysis;
-using System.IO;
-using System.Linq;
-using System.Reflection;
-using System.Runtime.ExceptionServices;
-using System.Text;
-using System.Text.Json;
-using System.Text.Json.Serialization;
-using System.Text.Json.Serialization.Metadata;
-using System.Threading.Tasks;
-using Microsoft.Extensions.Logging;
-using Microsoft.Maui.Handlers;
-using Microsoft.Maui.Platform;
-
-namespace Microsoft.Maui;
-
-///
-/// Helper class containing all business logic for HybridWebView operations.
-/// Keeps both Controls and Handler layers thin by centralizing processing logic.
-///
-[RequiresUnreferencedCode("HybridWebView uses dynamic System.Text.Json serialization features.")]
-#if !NETSTANDARD
-[RequiresDynamicCode("HybridWebView uses dynamic System.Text.Json serialization features.")]
-#endif
-internal static partial class HybridWebViewHelper
-{
- ///
- /// Processes an EvaluateJavaScriptAsync request by wrapping the script with error handling
- /// and processing the result.
- ///
- public static async Task ProcessEvaluateJavaScriptAsync(IHybridWebViewHandler handler, IHybridWebView hybridWebView, EvaluateJavaScriptAsyncRequest request)
- {
- var script = request.Script;
-
- if (script == null)
- {
- return null;
- }
-
- // Escape and wrap script with try-catch and error handling
- var escapedScript = WebViewHelper.EscapeJsString(script);
- var wrappedScript =
- $$"""
- (function() {
- try {
- let result = eval('{{escapedScript}}');
- let resultObj = {
- IsError: false,
- Result: JSON.stringify(result)
- };
- return JSON.stringify(resultObj);
- } catch (error) {
- console.error(error);
- let errorObj;
- if (!error) {
- errorObj = {
- IsError: true,
- Message: 'Unknown error',
- StackTrace: Error().stack
- };
- } else if (error instanceof Error) {
- errorObj = {
- IsError: true,
- Name: error.name,
- Message: error.message,
- StackTrace: error.stack
- };
- } else if (typeof error === 'string') {
- errorObj = {
- IsError: true,
- Message: error,
- StackTrace: Error().stack
- };
- } else {
- errorObj = {
- IsError: true,
- Message: JSON.stringify(error),
- StackTrace: Error().stack
- };
- }
- return JSON.stringify(errorObj);
- }
- })()
- """;
-
- // Use the handler command to evaluate the JS
- var innerRequest = new EvaluateJavaScriptAsyncRequest(wrappedScript);
-
- // Execute via platform evaluator
- handler.PlatformView.EvaluateJavaScript(innerRequest);
-
- var result = await innerRequest.Task;
-
- if (result == null)
- return null;
-
- // Android's WebView automatically JSON-encodes the return value, so we need to unwrap it
- // Check if the result is a JSON-encoded string (starts and ends with quotes)
- if (OperatingSystem.IsAndroid())
- {
- // Deserialize once to unwrap the JSON string
- result = JsonSerializer.Deserialize(result);
- if (result == null)
- return null;
- }
-
- var jsResult = JsonSerializer.Deserialize(result, HybridWebViewHelperJsonContext.Default.JSInvokeResult);
- if (jsResult?.IsError == true)
- {
- var jsException = new HybridWebViewInvokeJavaScriptException(jsResult?.Message, jsResult?.Name, jsResult?.StackTrace);
- throw new HybridWebViewInvokeJavaScriptException($"EvaluateJavaScriptAsync threw an exception: {jsException.Message}", jsException);
- }
-
- var returnValue = jsResult?.Result;
-
- //if the js function errored or returned null/undefined treat it as null
- if (returnValue == "null" || returnValue == "undefined")
- {
- returnValue = null;
- }
- //JSON.stringify wraps the result - we need to unwrap it properly
- //note that if the js function returns the string "null" we will get here and not above
- else if (returnValue != null)
- {
- // Check if the result is a JSON string (starts and ends with quotes)
- if (returnValue.Length >= 2 && returnValue[0] == '"' && returnValue[^1] == '"')
- {
- // Properly deserialize the JSON string to handle escaped characters
- returnValue = JsonSerializer.Deserialize(returnValue);
- }
- // Otherwise it's a primitive value (number, boolean, etc.) that's already in string form
- // No need to deserialize - just return as-is
- }
-
- return returnValue;
- }
-
- ///
- /// Processes an InvokeJavaScriptAsync request by building the JS call string,
- /// executing it, and processing the result.
- ///
- public static async Task ProcessInvokeJavaScriptAsync(IHybridWebViewHandler handler, IHybridWebView hybridWebView, HybridWebViewInvokeJavaScriptRequest request)
- {
- var taskManager = handler.GetRequiredService();
-
- // Create a callback for async JavaScript methods to invoke when they are done
- var task = taskManager.CreateTask();
-
- var paramsValuesStringArray = request.ParamValues == null
- ? string.Empty
- : string.Join(
- ", ",
- request.ParamValues.Select((v, i) => v is null ? "null" : JsonSerializer.Serialize(v, request.ParamJsonTypeInfos![i]!)));
-
- var js = $"window.HybridWebView.__InvokeJavaScript({task.TaskId}, {request.MethodName}, [{paramsValuesStringArray}])";
-
- var innerRequest = new EvaluateJavaScriptAsyncRequest(js);
-
- handler.PlatformView.EvaluateJavaScript(innerRequest);
-
- // Don't await innerRequest.Task because __InvokeJavaScript is async and returns a Promise,
- // which iOS can't convert to a string. Instead, we wait for the callback message from JavaScript.
- // The JavaScript function will call invokeJavaScriptCallbackInDotNet() when done.
-
- var stringResult = await task.TaskCompletionSource.Task;
-
- // if there is no result or if the result was null/undefined, then treat it as null
- if (stringResult is null || stringResult == "null" || stringResult == "undefined")
- {
- return null;
- }
- // if we are not looking for a return object, then return null
- else if (request.ReturnTypeJsonTypeInfo is null)
- {
- return null;
- }
- // if we are expecting a result, then deserialize what we have
- else
- {
- var typedResult = JsonSerializer.Deserialize(stringResult, request.ReturnTypeJsonTypeInfo);
- return typedResult;
- }
- }
-
- ///
- /// Invokes a .NET method from JavaScript.
- ///
- public static async Task ProcessInvokeDotNetAsync(
- object? invokeTarget,
- [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] Type? invokeTargetType,
- ILogger? logger,
- Stream? streamBody = null,
- string? stringBody = null)
- {
- try
- {
- if (invokeTarget is null)
- {
- throw new InvalidOperationException($"The InvokeJavaScriptTarget property must have a value in order to invoke a .NET method from JavaScript.");
- }
-
- if (invokeTargetType is null)
- {
- throw new InvalidOperationException($"The InvokeJavaScriptType property must have a value in order to invoke a .NET method from JavaScript.");
- }
-
- JSInvokeMethodData? invokeData = null;
- if (streamBody is not null)
- {
- invokeData = await JsonSerializer.DeserializeAsync(streamBody, HybridWebViewHelperJsonContext.Default.JSInvokeMethodData);
- }
- else if (stringBody is not null && !string.IsNullOrWhiteSpace(stringBody))
- {
- invokeData = JsonSerializer.Deserialize(stringBody, HybridWebViewHelperJsonContext.Default.JSInvokeMethodData);
- }
-
- if (invokeData?.MethodName is null)
- {
- throw new InvalidOperationException("The invoke data did not provide a method name.");
- }
-
- var invokeResultRaw = await InvokeDotNetMethodAsync(invokeTargetType, invokeTarget, invokeData);
- var invokeResult = CreateInvokeResult(invokeResultRaw);
- var json = JsonSerializer.Serialize(invokeResult);
- var contentBytes = Encoding.UTF8.GetBytes(json);
-
- return contentBytes;
- }
- catch (Exception ex)
- {
- logger?.LogError(ex, "An error occurred while invoking a .NET method from JavaScript: {ErrorMessage}", ex.Message);
-
- // Return error response instead of null so JavaScript can handle the error
- var errorResult = CreateErrorResult(ex);
- var errorJson = JsonSerializer.Serialize(errorResult, HybridWebViewHelperJsonContext.Default.DotNetInvokeResult);
- var errorBytes = Encoding.UTF8.GetBytes(errorJson);
- return errorBytes;
- }
- }
-
- private static DotNetInvokeResult CreateInvokeResult(object? result)
- {
- // null invoke result means an empty result
- if (result is null)
- {
- return new();
- }
-
- // a reference type or an array should be serialized to JSON
- var resultType = result.GetType();
- if (resultType.IsArray || resultType.IsClass)
- {
- return new DotNetInvokeResult()
- {
- Result = JsonSerializer.Serialize(result),
- IsJson = true,
- };
- }
-
- // a value type should be returned as is
- return new DotNetInvokeResult()
- {
- Result = result,
- };
- }
-
- private static DotNetInvokeResult CreateErrorResult(Exception ex)
- {
- return new DotNetInvokeResult()
- {
- IsError = true,
- ErrorMessage = ex.Message,
- ErrorType = ex.GetType().Name,
- ErrorStackTrace = ex.StackTrace
- };
- }
-
- private static async Task InvokeDotNetMethodAsync(
- [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] Type targetType,
- object jsInvokeTarget,
- JSInvokeMethodData invokeData)
- {
- var requestMethodName = invokeData.MethodName!;
- var requestParams = invokeData.ParamValues;
-
- // get the method and its parameters from the .NET object instance
- var dotnetMethod = targetType.GetMethod(requestMethodName, BindingFlags.Public | BindingFlags.Instance | BindingFlags.InvokeMethod);
- if (dotnetMethod is null)
- {
- throw new InvalidOperationException($"The method {requestMethodName} couldn't be found on the {nameof(jsInvokeTarget)} of type {jsInvokeTarget.GetType().FullName}.");
- }
- var dotnetParams = dotnetMethod.GetParameters();
- if (requestParams is not null && dotnetParams.Length != requestParams.Length)
- {
- throw new InvalidOperationException($"The number of parameters on {nameof(jsInvokeTarget)}'s method {requestMethodName} ({dotnetParams.Length}) doesn't match the number of values passed from JavaScript code ({requestParams.Length}).");
- }
-
- // deserialize the parameters from JSON to .NET types
- object?[]? invokeParamValues = null;
- if (requestParams is not null)
- {
- invokeParamValues = new object?[requestParams.Length];
- for (var i = 0; i < requestParams.Length; i++)
- {
- var reqValue = requestParams[i];
- var paramType = dotnetParams[i].ParameterType;
- var deserialized = JsonSerializer.Deserialize(reqValue, paramType);
- invokeParamValues[i] = deserialized;
- }
- }
-
- // invoke the .NET method
- var dotnetReturnValue = GetDotNetMethodReturnValue(jsInvokeTarget, dotnetMethod, invokeParamValues);
-
- if (dotnetReturnValue is null) // null result
- {
- return null;
- }
-
- if (dotnetReturnValue is Task task) // Task or Task result
- {
- await task;
-
- // Task
- if (dotnetMethod.ReturnType.IsGenericType)
- {
- var resultProperty = dotnetMethod.ReturnType.GetProperty(nameof(Task.Result));
- return resultProperty?.GetValue(task);
- }
-
- // Task
- return null;
- }
-
- return dotnetReturnValue; // regular result
- }
-
- private static object? GetDotNetMethodReturnValue(object jsInvokeTarget, MethodInfo dotnetMethod, object?[]? invokeParamValues)
- {
- try
- {
- // invoke the .NET method
- return dotnetMethod.Invoke(jsInvokeTarget, invokeParamValues);
- }
- catch (TargetInvocationException tie) // unwrap while preserving original stack trace
- {
- if (tie.InnerException is not null)
- {
- // Rethrow the underlying exception without losing its original stack trace
- ExceptionDispatchInfo.Capture(tie.InnerException).Throw();
-
- // unreachable, but required for compiler flow analysis
- throw;
- }
-
- // no inner exception; rethrow the TargetInvocationException itself preserving its stack
- throw;
- }
- }
-
- ///
- /// Processes raw messages from the web view, handling special message types like JavaScript invoke results.
- ///
- public static void ProcessRawMessage(IHybridWebViewHandler handler, IHybridWebView virtualView, string rawMessage)
- {
- if (string.IsNullOrEmpty(rawMessage))
- {
- throw new ArgumentException($"The raw message cannot be null or empty.", nameof(rawMessage));
- }
-#if !NETSTANDARD2_0
- var indexOfPipe = rawMessage.IndexOf('|', StringComparison.Ordinal);
-#else
- var indexOfPipe = rawMessage.IndexOf("|", StringComparison.Ordinal);
-#endif
- if (indexOfPipe == -1)
- {
- throw new ArgumentException($"The raw message must contain a pipe character ('|').", nameof(rawMessage));
- }
-
- var messageType = rawMessage.Substring(0, indexOfPipe);
- var messageContent = rawMessage.Substring(indexOfPipe + 1);
-
- switch (messageType)
- {
- case "__InvokeJavaScriptFailed":
- case "__InvokeJavaScriptCompleted":
- {
-#if !NETSTANDARD2_0
- var indexOfPipeInContent = messageContent.IndexOf('|', StringComparison.Ordinal);
-#else
- var indexOfPipeInContent = messageContent.IndexOf("|", StringComparison.Ordinal);
-#endif
- if (indexOfPipeInContent == -1)
- {
- throw new ArgumentException($"The '{messageType}' message content must contain a pipe character ('|').", nameof(rawMessage));
- }
-
- var taskId = messageContent.Substring(0, indexOfPipeInContent);
- var result = messageContent.Substring(indexOfPipeInContent + 1);
-
- var taskManager = handler.GetRequiredService();
- if (messageType == "__InvokeJavaScriptFailed")
- {
- if (IsInvokeJavaScriptThrowsExceptionsEnabled)
- {
- if (string.IsNullOrWhiteSpace(result))
- {
- taskManager.SetTaskFailed(taskId, new HybridWebViewInvokeJavaScriptException());
- }
- else
- {
- var jsError = JsonSerializer.Deserialize(result, HybridWebViewHelperJsonContext.Default.JSInvokeError);
- var jsException = new HybridWebViewInvokeJavaScriptException(jsError?.Message, jsError?.Name, jsError?.StackTrace);
- var ex = new HybridWebViewInvokeJavaScriptException($"InvokeJavaScriptAsync threw an exception: {jsException.Message}", jsException);
- taskManager.SetTaskFailed(taskId, ex);
- }
- }
- }
- else
- {
- taskManager.SetTaskCompleted(taskId, result);
- }
- }
- break;
- case "__RawMessage":
- virtualView?.RawMessageReceived(messageContent);
- break;
- default:
- throw new ArgumentException($"The message type '{messageType}' is not recognized.", nameof(rawMessage));
- }
- }
-
- private const string InvokeJavaScriptThrowsExceptionsSwitch = "HybridWebView.InvokeJavaScriptThrowsExceptions";
-
- private static bool IsInvokeJavaScriptThrowsExceptionsEnabled =>
- !AppContext.TryGetSwitch(InvokeJavaScriptThrowsExceptionsSwitch, out var enabled) || enabled;
-
- // DTOs for JSON serialization
- internal sealed class JSInvokeResult
- {
- public string? Result { get; set; }
- public bool IsError { get; set; }
- public string? Name { get; set; }
- public string? Message { get; set; }
- public string? StackTrace { get; set; }
- }
-
- internal sealed class JSInvokeMethodData
- {
- public string? MethodName { get; set; }
- public string[]? ParamValues { get; set; }
- }
-
- internal sealed class JSInvokeError
- {
- public string? Name { get; set; }
- public string? Message { get; set; }
- public string? StackTrace { get; set; }
- }
-
- internal sealed class DotNetInvokeResult
- {
- public object? Result { get; set; }
- public bool IsJson { get; set; }
- public bool IsError { get; set; }
- public string? ErrorMessage { get; set; }
- public string? ErrorType { get; set; }
- public string? ErrorStackTrace { get; set; }
- }
-
- [JsonSourceGenerationOptions()]
- [JsonSerializable(typeof(JSInvokeResult))]
- [JsonSerializable(typeof(JSInvokeMethodData))]
- [JsonSerializable(typeof(JSInvokeError))]
- [JsonSerializable(typeof(DotNetInvokeResult))]
- internal partial class HybridWebViewHelperJsonContext : JsonSerializerContext
- {
- }
-}
-#endif
diff --git a/src/Core/src/Handlers/Switch/SwitchHandler.iOS.cs b/src/Core/src/Handlers/Switch/SwitchHandler.iOS.cs
index 6fab7dbe3fc1..01fc9c0bb7a7 100644
--- a/src/Core/src/Handlers/Switch/SwitchHandler.iOS.cs
+++ b/src/Core/src/Handlers/Switch/SwitchHandler.iOS.cs
@@ -3,7 +3,6 @@
using CoreFoundation;
using Foundation;
using Microsoft.Maui.Graphics;
-using Microsoft.Maui.Platform;
using ObjCRuntime;
using UIKit;
using RectangleF = CoreGraphics.CGRect;
@@ -70,7 +69,6 @@ class SwitchProxy
NSObject? _willEnterForegroundObserver;
NSObject? _windowDidBecomeKeyObserver;
- IUITraitChangeRegistration? _traitChangeRegistration;
public void Connect(ISwitch virtualView, UISwitch platformView)
{
@@ -85,10 +83,6 @@ public void Connect(ISwitch virtualView, UISwitch platformView)
if (PlatformView is not null)
{
UpdateTrackOffColor(PlatformView);
- if (OperatingSystem.IsMacCatalystVersionAtLeast(26))
- {
- UpdateThumbColor(PlatformView);
- }
}
});
#elif IOS
@@ -101,28 +95,6 @@ public void Connect(ISwitch virtualView, UISwitch platformView)
}
});
#endif
-
- // iOS/MacCatalyst 26+ resets ThumbTintColor when theme changes (light/dark mode).
- // Register for trait changes to re-apply ThumbColor after UIKit completes its styling.
- if (OperatingSystem.IsIOSVersionAtLeast(26) || OperatingSystem.IsMacCatalystVersionAtLeast(26))
- {
- if (_traitChangeRegistration is not null)
- {
- platformView.UnregisterForTraitChanges(_traitChangeRegistration);
- }
-
- _traitChangeRegistration = platformView.RegisterForTraitChanges(
- (IUITraitEnvironment view, UITraitCollection _) =>
- {
- if (view is UISwitch uiSwitch)
- {
- UpdateThumbColor(uiSwitch);
- }
- });
-
- // iOS 26+ resets ThumbTintColor after initial layout, so re-apply the custom ThumbColor here.
- UpdateThumbColor(platformView);
- }
}
// Ensures the Switch track "OFF" color is updated correctly after system-level UI resets.
@@ -144,22 +116,6 @@ void UpdateTrackOffColor(UISwitch platformView)
});
}
- void UpdateThumbColor(UISwitch platformView)
- {
- DispatchQueue.MainQueue.DispatchAsync(async () =>
- {
- if (VirtualView is null || PlatformView is null)
- return;
-
- await Task.Delay(10); // Small delay, necessary to allow UIKit to complete its internal layout and styling processes before re-applying the custom color
-
- if (VirtualView is ISwitch view && view.ThumbColor is not null)
- {
- platformView.UpdateThumbColor(view);
- }
- });
- }
-
public void Disconnect(UISwitch platformView)
{
platformView.ValueChanged -= OnControlValueChanged;
@@ -174,11 +130,6 @@ public void Disconnect(UISwitch platformView)
NSNotificationCenter.DefaultCenter.RemoveObserver(_windowDidBecomeKeyObserver);
_windowDidBecomeKeyObserver = null;
}
- if (_traitChangeRegistration is not null)
- {
- platformView.UnregisterForTraitChanges(_traitChangeRegistration);
- _traitChangeRegistration = null;
- }
}
void OnControlValueChanged(object? sender, EventArgs e)
diff --git a/src/Core/src/Handlers/TimePicker/TimePickerHandler.Android.cs b/src/Core/src/Handlers/TimePicker/TimePickerHandler.Android.cs
index 352cad08617c..b67518027ae6 100644
--- a/src/Core/src/Handlers/TimePicker/TimePickerHandler.Android.cs
+++ b/src/Core/src/Handlers/TimePicker/TimePickerHandler.Android.cs
@@ -5,8 +5,6 @@
using Android.Graphics.Drawables;
using Android.Text.Format;
using DateFormat = Android.Text.Format.DateFormat;
-using Android.Views;
-using Microsoft.Maui.Devices;
namespace Microsoft.Maui.Handlers
{
@@ -28,24 +26,6 @@ protected override void ConnectHandler(MauiTimePicker platformView)
platformView.ShowPicker = ShowPickerDialog;
platformView.HidePicker = HidePickerDialog;
- platformView.ViewAttachedToWindow += OnViewAttachedToWindow;
- platformView.ViewDetachedFromWindow += OnViewDetachedFromWindow;
-
- if (platformView.IsAttachedToWindow)
- {
- OnViewAttachedToWindow();
- }
- }
-
- void OnViewDetachedFromWindow(object? sender = null, View.ViewDetachedFromWindowEventArgs? e = null)
- {
- // Called when an activity is destroyed or view is detached
- DeviceDisplay.MainDisplayInfoChanged -= OnMainDisplayInfoChanged;
- }
-
- void OnViewAttachedToWindow(object? sender = null, View.ViewAttachedToWindowEventArgs? e = null)
- {
- DeviceDisplay.MainDisplayInfoChanged += OnMainDisplayInfoChanged;
}
protected override void DisconnectHandler(MauiTimePicker platformView)
@@ -57,14 +37,8 @@ protected override void DisconnectHandler(MauiTimePicker platformView)
_dialog = null;
}
- platformView.ViewAttachedToWindow -= OnViewAttachedToWindow;
- platformView.ViewDetachedFromWindow -= OnViewDetachedFromWindow;
- OnViewDetachedFromWindow();
-
platformView.ShowPicker = null;
platformView.HidePicker = null;
-
- base.DisconnectHandler(platformView);
}
protected virtual TimePickerDialog CreateTimePickerDialog(int hour, int minute)
@@ -117,22 +91,6 @@ public static void MapFont(ITimePickerHandler handler, ITimePicker timePicker)
handler.PlatformView?.UpdateFont(timePicker, fontManager);
}
- // Make it public in .NET 11.
- internal static void MapFlowDirection(ITimePickerHandler handler, ITimePicker timePicker)
- {
- if (handler.PlatformView is not null)
- {
- handler.PlatformView.UpdateFlowDirection(timePicker);
-
- // For 12-hour format, also apply text alignment to handle AM/PM positioning
- // For 24-hour format, UpdateFlowDirection alone is sufficient
- if (handler is TimePickerHandler timePickerHandler && !timePickerHandler.Use24HourView)
- {
- handler.PlatformView.UpdateTextAlignment(timePicker);
- }
- }
- }
-
public static void MapTextColor(ITimePickerHandler handler, ITimePicker timePicker)
{
handler.PlatformView?.UpdateTextColor(timePicker);
@@ -216,20 +174,5 @@ bool Use24HourView
return IsCustom24HourFormat(VirtualView.Format);
}
}
-
- void OnMainDisplayInfoChanged(object? sender, DisplayInfoChangedEventArgs e)
- {
- // Only handle orientation changes when dialog is actually showing
- if (_dialog is not null && _dialog.IsShowing)
- {
- // Unsubscribe first to prevent the DismissEvent from hiding the new dialog
- _dialog.DismissEvent -= OnDialogDismiss;
- _dialog.Dismiss();
- _dialog = null;
-
- // Recreate dialog with current values to handle orientation change
- ShowPickerDialog(VirtualView?.Time);
- }
- }
}
}
\ No newline at end of file
diff --git a/src/Core/src/Handlers/TimePicker/TimePickerHandler.Windows.cs b/src/Core/src/Handlers/TimePicker/TimePickerHandler.Windows.cs
index 3006bdae13ef..6820908bdfdc 100644
--- a/src/Core/src/Handlers/TimePicker/TimePickerHandler.Windows.cs
+++ b/src/Core/src/Handlers/TimePicker/TimePickerHandler.Windows.cs
@@ -1,5 +1,4 @@
using Microsoft.UI.Xaml.Controls;
-using Microsoft.UI.Xaml;
using WBrush = Microsoft.UI.Xaml.Media.Brush;
namespace Microsoft.Maui.Handlers
diff --git a/src/Core/src/Handlers/TimePicker/TimePickerHandler.cs b/src/Core/src/Handlers/TimePicker/TimePickerHandler.cs
index b8b8d030b283..6ba3d841a365 100644
--- a/src/Core/src/Handlers/TimePicker/TimePickerHandler.cs
+++ b/src/Core/src/Handlers/TimePicker/TimePickerHandler.cs
@@ -20,8 +20,7 @@ public partial class TimePickerHandler : ITimePickerHandler
{
#if ANDROID || WINDOWS
[nameof(ITimePicker.Background)] = MapBackground,
-#endif
-#if IOS || ANDROID
+#elif IOS
[nameof(ITimePicker.FlowDirection)] = MapFlowDirection,
#endif
[nameof(ITimePicker.CharacterSpacing)] = MapCharacterSpacing,
diff --git a/src/Core/src/Handlers/TimePicker/TimePickerHandler.iOS.cs b/src/Core/src/Handlers/TimePicker/TimePickerHandler.iOS.cs
index caddf83802b7..a8bca69afb31 100644
--- a/src/Core/src/Handlers/TimePicker/TimePickerHandler.iOS.cs
+++ b/src/Core/src/Handlers/TimePicker/TimePickerHandler.iOS.cs
@@ -62,16 +62,6 @@ public static void MapFlowDirection(TimePickerHandler handler, ITimePicker timeP
handler.PlatformView?.UpdateTextAlignment(timePicker);
}
- // Make it public in .NET 11 and remove the concrete TimePickerHandler overload.
- internal static void MapFlowDirection(ITimePickerHandler handler, ITimePicker timePicker)
- {
- if (handler.PlatformView is not null)
- {
- handler.PlatformView.UpdateFlowDirection(timePicker);
- handler.PlatformView.UpdateTextAlignment(timePicker);
- }
- }
-
internal static void MapIsOpen(ITimePickerHandler handler, ITimePicker timePicker)
{
handler.PlatformView?.UpdateIsOpen(timePicker);
diff --git a/src/Core/src/Platform/Android/ContainerView.cs b/src/Core/src/Platform/Android/ContainerView.cs
index ac08d57731ef..20d0d131bf71 100644
--- a/src/Core/src/Platform/Android/ContainerView.cs
+++ b/src/Core/src/Platform/Android/ContainerView.cs
@@ -20,9 +20,7 @@ protected ContainerView(IntPtr javaReference, JniHandleOwnership transfer)
}
public ContainerView(IMauiContext context)
- : base(context.Context ?? throw new InvalidOperationException(
- "Unable to create a ContainerView: the Android Context is no longer available. " +
- "This can occur when the Activity has been collected during a lifecycle transition."))
+ : base(context.Context)
{
_context = context;
}
diff --git a/src/Core/src/Platform/Android/MauiWebView.cs b/src/Core/src/Platform/Android/MauiWebView.cs
index cabe0fab49e5..4e787356d850 100644
--- a/src/Core/src/Platform/Android/MauiWebView.cs
+++ b/src/Core/src/Platform/Android/MauiWebView.cs
@@ -1,7 +1,6 @@
using System;
using Android.Content;
using Android.Graphics;
-using Android.Views;
using Android.Webkit;
namespace Microsoft.Maui.Platform
@@ -43,27 +42,6 @@ protected override void OnSizeChanged(int width, int height, int oldWidth, int o
}
}
- public override bool OnTouchEvent(MotionEvent? e)
- {
- if (e == null)
- return false;
-
- switch (e.Action)
- {
- case MotionEventActions.Down:
- case MotionEventActions.Move:
- Parent?.RequestDisallowInterceptTouchEvent(true);
- break;
-
- case MotionEventActions.Up:
- case MotionEventActions.Cancel:
- Parent?.RequestDisallowInterceptTouchEvent(false);
- break;
- }
-
- return base.OnTouchEvent(e);
- }
-
void IWebViewDelegate.LoadHtml(string? html, string? baseUrl)
{
_handler?.CurrentNavigationEvent = WebNavigationEvent.NewPage;
diff --git a/src/Core/src/Platform/Android/TimePickerExtensions.cs b/src/Core/src/Platform/Android/TimePickerExtensions.cs
index 5f9259874a25..e6917fe89280 100644
--- a/src/Core/src/Platform/Android/TimePickerExtensions.cs
+++ b/src/Core/src/Platform/Android/TimePickerExtensions.cs
@@ -1,7 +1,6 @@
using System;
using Android.Content.Res;
using AndroidX.AppCompat.Widget;
-using ATextAlignment = Android.Views.TextAlignment;
namespace Microsoft.Maui.Platform;
@@ -60,12 +59,4 @@ static void UpdateTextColorImpl(AppCompatEditText platformTimePicker, ITimePicke
}
}
}
-
- // Make it public in .NET 11.
- internal static void UpdateTextAlignment(this MauiTimePicker mauiTimePicker, ITimePicker timePicker)
- {
- mauiTimePicker.TextAlignment = timePicker.FlowDirection == FlowDirection.RightToLeft
- ? ATextAlignment.TextEnd
- : ATextAlignment.TextStart;
- }
-}
+}
\ No newline at end of file
diff --git a/src/Core/src/Platform/Windows/ContentPanel.cs b/src/Core/src/Platform/Windows/ContentPanel.cs
index b6465846f81a..61c4e6677e2a 100644
--- a/src/Core/src/Platform/Windows/ContentPanel.cs
+++ b/src/Core/src/Platform/Windows/ContentPanel.cs
@@ -1,5 +1,4 @@
using System;
-using System.Collections.Generic;
using System.Numerics;
using Microsoft.Graphics.Canvas;
using Microsoft.Maui.Graphics;
@@ -10,8 +9,6 @@
#endif
using Microsoft.UI.Composition;
using Microsoft.UI.Xaml;
-using Microsoft.UI.Xaml.Automation;
-using Microsoft.UI.Xaml.Automation.Peers;
using Microsoft.UI.Xaml.Hosting;
using Microsoft.UI.Xaml.Shapes;
@@ -76,25 +73,6 @@ public ContentPanel()
SizeChanged += ContentPanelSizeChanged;
}
- // Custom automation peer prevents duplicate announcements when AutomationProperties.Name is set
- protected override AutomationPeer OnCreateAutomationPeer() => new ContentPanelAutomationPeer(this);
-
- internal partial class ContentPanelAutomationPeer : FrameworkElementAutomationPeer
- {
- internal ContentPanelAutomationPeer(ContentPanel owner) : base(owner) { }
-
- bool HasDescription => !string.IsNullOrWhiteSpace(AutomationProperties.GetName(Owner));
-
- protected override AutomationControlType GetAutomationControlTypeCore() =>
- HasDescription ? AutomationControlType.Text : AutomationControlType.Custom;
-
- protected override string GetLocalizedControlTypeCore() =>
- HasDescription ? string.Empty : base.GetLocalizedControlTypeCore() ?? string.Empty;
-
- protected override IList? GetChildrenCore() =>
- HasDescription ? null : base.GetChildrenCore();
- }
-
void ContentPanelSizeChanged(object sender, SizeChangedEventArgs e)
{
if (_borderPath is null)
diff --git a/src/Core/src/Platform/Windows/MauiPasswordTextBox.cs b/src/Core/src/Platform/Windows/MauiPasswordTextBox.cs
index fb2aaa9f6500..ca9b594b3b17 100644
--- a/src/Core/src/Platform/Windows/MauiPasswordTextBox.cs
+++ b/src/Core/src/Platform/Windows/MauiPasswordTextBox.cs
@@ -334,7 +334,7 @@ static string DetermineTextFromPassword(string realText, int start, string passw
var lengthDifference = passwordText.Length - realText.Length;
if (lengthDifference > 0)
- realText = realText.Insert(Math.Max(0, start - lengthDifference), new string(ObfuscationCharacter, lengthDifference));
+ realText = realText.Insert(start - lengthDifference, new string(ObfuscationCharacter, lengthDifference));
else if (lengthDifference < 0)
realText = realText.Remove(start, -lengthDifference);
diff --git a/src/Core/src/Platform/Windows/RootNavigationView.cs b/src/Core/src/Platform/Windows/RootNavigationView.cs
index c43ccac44a68..1311a2870b99 100644
--- a/src/Core/src/Platform/Windows/RootNavigationView.cs
+++ b/src/Core/src/Platform/Windows/RootNavigationView.cs
@@ -26,7 +26,6 @@ public RootNavigationView()
PaneDisplayMode = NavigationViewPaneDisplayMode.LeftMinimal;
IsTitleBarAutoPaddingEnabled = false;
IsBackButtonVisible = NavigationViewBackButtonVisible.Collapsed;
- AlwaysShowHeader = false;
RegisterPropertyChangedCallback(IsBackButtonVisibleProperty, BackButtonVisibleChanged);
RegisterPropertyChangedCallback(OpenPaneLengthProperty, PaneLengthPropertyChanged);
@@ -56,7 +55,6 @@ public RootNavigationView()
UpdateToolbarPlacement();
UpdateHeaderPropertyBinding();
- UpdateHeaderVisibility();
}
}
@@ -70,7 +68,6 @@ void PaneDisplayModeChanged(DependencyObject sender, DependencyProperty dp)
{
UpdateToolbarPlacement();
UpdatePaneContentGridMargin();
- UpdateHeaderVisibility();
}
@@ -255,54 +252,6 @@ internal void UpdateAppTitleBar(double appTitleBarHeight, bool useCustomAppTitle
UpdateNavigationAndPaneButtonHolderGridStyles();
}
- internal void UpdateHeaderVisibility()
- {
- if (Toolbar is null || PaneDisplayMode != NavigationViewPaneDisplayMode.LeftMinimal)
- {
- return;
- }
-
- if (IsHeaderContentEmpty())
- {
- CollapseEmptyHeader();
- }
- else if (TopNavArea is not null &&
- (PaneFooter == Toolbar || Header is null))
- {
- Header = Toolbar;
- }
- }
-
- bool IsHeaderContentEmpty()
- {
- return string.IsNullOrEmpty(Toolbar?.Title) &&
- Toolbar?.TitleView is null &&
- !HasMenuBarItems() &&
- !HasToolbarItems() &&
- !HasTitleIcon();
- }
-
- bool HasMenuBarItems() => Toolbar?.HasMenuBarContent ?? false;
-
- bool HasToolbarItems()
- {
- if (Toolbar?.CommandBar == null)
- return false;
-
- return Toolbar?.CommandBar.PrimaryCommands.Count > 0 ||
- Toolbar?.CommandBar.SecondaryCommands.Count > 0;
- }
-
- bool HasTitleIcon() => Toolbar?.TitleIconImage?.Visibility == UI.Xaml.Visibility.Visible;
-
- void CollapseEmptyHeader()
- {
- if (Header is not null)
- {
- Header = null;
- }
- }
-
void UpdateNavigationAndPaneButtonHolderGridStyles()
{
var buttonHeight = Math.Max(_appBarTitleHeight, DefaultNavigationBackButtonHeight);
diff --git a/src/Core/src/Platform/Windows/TimePickerExtensions.cs b/src/Core/src/Platform/Windows/TimePickerExtensions.cs
index 85101e230b90..c9fe3a01c695 100644
--- a/src/Core/src/Platform/Windows/TimePickerExtensions.cs
+++ b/src/Core/src/Platform/Windows/TimePickerExtensions.cs
@@ -28,18 +28,6 @@ public static void UpdateTime(this TimePicker nativeTimePicker, ITimePicker time
public static void UpdateCharacterSpacing(this TimePicker platformTimePicker, ITimePicker timePicker)
{
platformTimePicker.CharacterSpacing = timePicker.CharacterSpacing.ToEm();
- if (!platformTimePicker.IsLoaded)
- {
- RoutedEventHandler? onLoaded = null;
- onLoaded = (s, e) =>
- {
- platformTimePicker.Loaded -= onLoaded;
- UpdateCharacterSpacingInTimePicker(platformTimePicker);
- };
- platformTimePicker.Loaded += onLoaded;
- return;
- }
- UpdateCharacterSpacingInTimePicker(platformTimePicker);
}
public static void UpdateFont(this TimePicker platformTimePicker, ITimePicker timePicker, IFontManager fontManager) =>
@@ -93,25 +81,6 @@ public static void UpdateBackground(this TimePicker platformTimePicker, ITimePic
platformTimePicker.RefreshThemeResources();
}
- static readonly string[] s_timePickerTextBlockNames = { "HourTextBlock", "MinuteTextBlock", "PeriodTextBlock" };
-
- static void UpdateCharacterSpacingInTimePicker(this TimePicker platformTimePicker)
- {
- foreach (var partName in s_timePickerTextBlockNames)
- {
- SetCharacterSpacingToBlocks(platformTimePicker, partName);
- }
- }
-
- static void SetCharacterSpacingToBlocks(TimePicker platformTimePicker, string partName)
- {
- var textBlock = platformTimePicker.GetDescendantByName(partName);
- if (textBlock is not null)
- {
- textBlock.CharacterSpacing = platformTimePicker.CharacterSpacing;
- }
- }
-
static readonly string[] BackgroundColorResourceKeys =
{
"TimePickerButtonBackground",
diff --git a/src/Core/src/Platform/iOS/ButtonExtensions.cs b/src/Core/src/Platform/iOS/ButtonExtensions.cs
index ac5a00c452c0..91ba7fd4eaef 100644
--- a/src/Core/src/Platform/iOS/ButtonExtensions.cs
+++ b/src/Core/src/Platform/iOS/ButtonExtensions.cs
@@ -1,5 +1,4 @@
using System;
-using Microsoft.Maui.Graphics;
using UIKit;
namespace Microsoft.Maui.Platform
@@ -32,19 +31,7 @@ public static void UpdateText(this UIButton platformButton, IText button) =>
public static void UpdateTextColor(this UIButton platformButton, ITextStyle button)
{
if (button.TextColor is null)
- {
- // Only clear explicit overrides when attached to a window.
- // Skipping during initial render prevents clearing Appearance-proxy colors.
- if (platformButton.Window is UIWindow window)
- {
- platformButton.SetTitleColor(null, UIControlState.Normal);
- platformButton.SetTitleColor(null, UIControlState.Highlighted);
- platformButton.SetTitleColor(null, UIControlState.Disabled);
- platformButton.TintColor = window.TintColor;
- }
-
return;
- }
var color = button.TextColor.ToPlatform();
@@ -55,24 +42,6 @@ public static void UpdateTextColor(this UIButton platformButton, ITextStyle butt
platformButton.TintColor = color;
}
- // TODO: Make this public in .NET 11
- internal static void UpdateBackground(this UIButton platformButton, Graphics.Paint? paint)
- {
- // Remove previous background gradient layer if any
- platformButton.RemoveBackgroundLayer();
-
- if (paint.IsNullOrEmpty())
- {
- // Reset to clear background for buttons when paint is null.
- // UIColor.Clear ensures proper transparency when VisualState setters are unapplied.
- platformButton.BackgroundColor = UIColor.Clear;
- return;
- }
-
- // Delegate to the standard view background update
- ViewExtensions.UpdateBackground(platformButton, paint);
- }
-
public static void UpdateCharacterSpacing(this UIButton platformButton, ITextStyle textStyle)
{
var attributedText = platformButton?.TitleLabel.AttributedText?.WithCharacterSpacing(textStyle.CharacterSpacing);
diff --git a/src/Core/src/Platform/iOS/LayerExtensions.cs b/src/Core/src/Platform/iOS/LayerExtensions.cs
index f5bdb6afc460..45808a9d9245 100644
--- a/src/Core/src/Platform/iOS/LayerExtensions.cs
+++ b/src/Core/src/Platform/iOS/LayerExtensions.cs
@@ -14,12 +14,6 @@ public static void InsertBackgroundLayer(this UIView control, CALayer background
{
var layer = control.Layer;
- // Ensure the background layer always renders behind subview layers,
- // even if UIKit reorganizes the sublayer array during layout passes.
- // Setting ZPosition before insertion is safe — it's a property on the
- // layer object and only takes effect once added to the sublayer hierarchy.
- backgroundLayer.ZPosition = -1;
-
if (index > -1)
layer.InsertSublayer(backgroundLayer, index);
else
diff --git a/src/Core/src/Platform/iOS/MauiView.cs b/src/Core/src/Platform/iOS/MauiView.cs
index 4518f5538daf..68439a781489 100644
--- a/src/Core/src/Platform/iOS/MauiView.cs
+++ b/src/Core/src/Platform/iOS/MauiView.cs
@@ -144,10 +144,6 @@ static UIEdgeInsets ComputeCellSafeAreaInsets(UIView cell, ISafeAreaView2 safeVi
// Null means not yet determined. Invalidated when view hierarchy changes.
bool? _parentHandlesSafeArea;
- // Indicates whether the measure invalidation has already been propagated
- // to ancestors during this main loop.
- bool _measureInvalidatedPropagated;
-
// Keyboard tracking
CGRect _keyboardFrame = CGRect.Empty;
bool _isKeyboardShowing;
@@ -625,10 +621,6 @@ void CrossPlatformArrange(CGRect bounds)
/// The size that fits within the constraints
public override CGSize SizeThatFits(CGSize size)
{
- // Invalidations shouldn't happen during measure pass,
- // but we need to support that in case it happens.
- _measureInvalidatedPropagated = false;
-
if (_crossPlatformLayoutReference == null)
{
return base.SizeThatFits(size);
@@ -661,9 +653,6 @@ public override void LayoutSubviews()
{
base.LayoutSubviews();
- // Allow measure invalidations during layout pass
- _measureInvalidatedPropagated = false;
-
if (_crossPlatformLayoutReference == null)
{
return;
@@ -810,12 +799,6 @@ bool IPlatformMeasureInvalidationController.InvalidateMeasure(bool isPropagating
// If we're not propagating, then this view is the one triggering the invalidation
// and one possible cause is that constraints have changed, so we have to propagate the invalidation.
- if (_measureInvalidatedPropagated)
- {
- return false;
- }
-
- _measureInvalidatedPropagated = true;
return true;
}
diff --git a/src/Core/src/Platform/iOS/TimePickerExtensions.cs b/src/Core/src/Platform/iOS/TimePickerExtensions.cs
index 2df0393787a1..4784340feb38 100644
--- a/src/Core/src/Platform/iOS/TimePickerExtensions.cs
+++ b/src/Core/src/Platform/iOS/TimePickerExtensions.cs
@@ -91,9 +91,7 @@ public static void UpdateTime(this MauiTimePicker mauiTimePicker, ITimePicker ti
public static void UpdateTextAlignment(this MauiTimePicker textField, ITimePicker timePicker)
{
- UISemanticContentAttribute updateValue = textField.SemanticContentAttribute;
-
- textField.TextAlignment = (updateValue == UISemanticContentAttribute.ForceRightToLeft) ? UITextAlignment.Right : UITextAlignment.Left;
+ // TODO: Update TextAlignment based on the EffectiveFlowDirection property.
}
internal static void UpdateIsOpen(this UIDatePicker picker, ITimePicker timePicker)
diff --git a/src/Core/src/Platform/iOS/WrapperView.cs b/src/Core/src/Platform/iOS/WrapperView.cs
index 65ad129e0a65..b75189a2f877 100644
--- a/src/Core/src/Platform/iOS/WrapperView.cs
+++ b/src/Core/src/Platform/iOS/WrapperView.cs
@@ -99,11 +99,10 @@ public override void LayoutSubviews()
return;
if (_borderView is not null)
- {
BringSubviewToFront(_borderView);
- }
var child = subviews[0];
+
child.Frame = Bounds;
if (MaskLayer is not null)
diff --git a/src/Core/src/PublicAPI/net-android/PublicAPI.Unshipped.txt b/src/Core/src/PublicAPI/net-android/PublicAPI.Unshipped.txt
index cf3ca2bcb9b7..fb0a201cd746 100644
--- a/src/Core/src/PublicAPI/net-android/PublicAPI.Unshipped.txt
+++ b/src/Core/src/PublicAPI/net-android/PublicAPI.Unshipped.txt
@@ -14,4 +14,3 @@ override Microsoft.Maui.Platform.LayoutViewGroup.HasOverlappingRendering.get ->
override Microsoft.Maui.Platform.WrapperView.HasOverlappingRendering.get -> bool
override Microsoft.Maui.Platform.MauiHybridWebView.OnSizeChanged(int width, int height, int oldWidth, int oldHeight) -> void
override Microsoft.Maui.Platform.MauiWebView.OnSizeChanged(int width, int height, int oldWidth, int oldHeight) -> void
-override Microsoft.Maui.Platform.MauiWebView.OnTouchEvent(Android.Views.MotionEvent? e) -> bool
diff --git a/src/Core/src/PublicAPI/net-ios/PublicAPI.Unshipped.txt b/src/Core/src/PublicAPI/net-ios/PublicAPI.Unshipped.txt
index 49a4403157a9..46f10522b960 100644
--- a/src/Core/src/PublicAPI/net-ios/PublicAPI.Unshipped.txt
+++ b/src/Core/src/PublicAPI/net-ios/PublicAPI.Unshipped.txt
@@ -5,6 +5,4 @@ override Microsoft.Maui.Handlers.StepperHandler.GetDesiredSize(double widthConst
override Microsoft.Maui.Platform.MauiTextView.TextAlignment.get -> UIKit.UITextAlignment
override Microsoft.Maui.Platform.MauiTextView.TextAlignment.set -> void
override Microsoft.Maui.Platform.MauiView.DidUpdateFocus(UIKit.UIFocusUpdateContext! context, UIKit.UIFocusAnimationCoordinator! coordinator) -> void
-static Microsoft.Maui.Handlers.EditorHandler.MapBackground(Microsoft.Maui.Handlers.IEditorHandler! handler, Microsoft.Maui.IEditor! editor) -> void
-static Microsoft.Maui.Handlers.EntryHandler.MapBackground(Microsoft.Maui.Handlers.IEntryHandler! handler, Microsoft.Maui.IEntry! entry) -> void
static Microsoft.Maui.Handlers.DatePickerHandler.MapFlowDirection(Microsoft.Maui.Handlers.IDatePickerHandler! handler, Microsoft.Maui.IDatePicker! datePicker) -> void
diff --git a/src/Core/src/PublicAPI/net-maccatalyst/PublicAPI.Unshipped.txt b/src/Core/src/PublicAPI/net-maccatalyst/PublicAPI.Unshipped.txt
index 49a4403157a9..46f10522b960 100644
--- a/src/Core/src/PublicAPI/net-maccatalyst/PublicAPI.Unshipped.txt
+++ b/src/Core/src/PublicAPI/net-maccatalyst/PublicAPI.Unshipped.txt
@@ -5,6 +5,4 @@ override Microsoft.Maui.Handlers.StepperHandler.GetDesiredSize(double widthConst
override Microsoft.Maui.Platform.MauiTextView.TextAlignment.get -> UIKit.UITextAlignment
override Microsoft.Maui.Platform.MauiTextView.TextAlignment.set -> void
override Microsoft.Maui.Platform.MauiView.DidUpdateFocus(UIKit.UIFocusUpdateContext! context, UIKit.UIFocusAnimationCoordinator! coordinator) -> void
-static Microsoft.Maui.Handlers.EditorHandler.MapBackground(Microsoft.Maui.Handlers.IEditorHandler! handler, Microsoft.Maui.IEditor! editor) -> void
-static Microsoft.Maui.Handlers.EntryHandler.MapBackground(Microsoft.Maui.Handlers.IEntryHandler! handler, Microsoft.Maui.IEntry! entry) -> void
static Microsoft.Maui.Handlers.DatePickerHandler.MapFlowDirection(Microsoft.Maui.Handlers.IDatePickerHandler! handler, Microsoft.Maui.IDatePicker! datePicker) -> void
diff --git a/src/Core/src/PublicAPI/net-windows/PublicAPI.Unshipped.txt b/src/Core/src/PublicAPI/net-windows/PublicAPI.Unshipped.txt
index cb86b4077b38..f02df3a74f88 100644
--- a/src/Core/src/PublicAPI/net-windows/PublicAPI.Unshipped.txt
+++ b/src/Core/src/PublicAPI/net-windows/PublicAPI.Unshipped.txt
@@ -1,3 +1,2 @@
#nullable enable
override Microsoft.Maui.Platform.MauiPasswordTextBox.OnCreateAutomationPeer() -> Microsoft.UI.Xaml.Automation.Peers.AutomationPeer!
-override Microsoft.Maui.Platform.ContentPanel.OnCreateAutomationPeer() -> Microsoft.UI.Xaml.Automation.Peers.AutomationPeer!
diff --git a/src/Core/tests/Benchmarks/Benchmarks/BindableObjectBenchmarker.cs b/src/Core/tests/Benchmarks/Benchmarks/BindableObjectBenchmarker.cs
deleted file mode 100644
index f768a4944c57..000000000000
--- a/src/Core/tests/Benchmarks/Benchmarks/BindableObjectBenchmarker.cs
+++ /dev/null
@@ -1,38 +0,0 @@
-using System.Linq;
-using BenchmarkDotNet.Attributes;
-using Microsoft.Maui.Controls;
-
-namespace Microsoft.Maui.Benchmarks
-{
- [MemoryDiagnoser]
- public class BindableObjectBenchmarker
- {
- BindableProperty[] _properties;
-
- [Params(1, 3, 8, 15, 30, 50)]
- public int PropertiesToSet { get; set; }
-
- [GlobalSetup]
- public void Setup()
- {
- _properties = Enumerable.Range(0, PropertiesToSet)
- .Select(i => BindableProperty.Create($"Property{i}", typeof(int), typeof(BindableObject), -1))
- .ToArray();
- }
-
- private class Bindable : BindableObject {}
-
- [Benchmark]
- public void SetsAndReadsProperties()
- {
- var bindable = new Bindable();
-
- var count = _properties.Length;
- for (int i = 0; i < count; i++)
- {
- bindable.SetValue(_properties[i], i);
- _ = bindable.GetValue(_properties[i]);
- }
- }
- }
-}
\ No newline at end of file