Repository navigation
[Android] Upgrade to 10.0.90 does not handle UI events properly #36942
Description
Description
In my Android app, I noticed that new UI-related bugs appeared right after upgrading MAUI.Controls (and Compat) from 10.0.80 to 10.0.90.
Here are 2 small clips showcasing the behavior change:
MAUI 10.0.80 - events are propagated correctly
10.0.80-events-propagation-ok-cropped.mp4
MAUI 10.0.90 - events are not propagated correctly to the UI (internal boolean properties is OK, but visual state only updates when toggling the parent section - toggles between Enabled/Disabled).
10.0.90-events-propagation-ko-cropped.mp4
Steps to Reproduce
A template project would be nice to write, I don't have the bandwidth to do so right now, I'll try to come up with a small repro project in few weeks.
Meanwhile, I think we could investigate the changes around event propagation.
My current hypotheses (potentially wrong indeed) are hovering around UI state propagation and event handling.
I also noticed that introducing breakpoints (while debugging) helped and within Android emulators and physical devices, having breakpoints will delay the process just enough for visual states to be updated correctly (hence why I describe it as "event storm" -> I believe some events are dropped/lost and that might be why the UI is not updating.
A strong pointer to this hypothesis is the fact that the parent section toggle switch (bound to the Enabled property of the Border control) re-triggers visual state update and it is enough to make the UI respond.
Note: I cannot update the code pages because Github won't let me update xaml pages.
<!-- Date filter -->
<Border Grid.Row="0"
x:Name="DateFilterBorder"
Stroke="{AppThemeBinding Light=#55111111, Dark=#55999999}"
StrokeShape="RoundRectangle 20"
StrokeThickness="1"
Padding="5">
<Grid RowDefinitions="auto,auto,auto,auto,auto"
RowSpacing="0">
<!-- Top part of the Date filter block -->
<Grid Grid.Row="0"
ColumnDefinitions="auto,auto,*,auto"
MaximumHeightRequest="30">
<Switch Grid.Column="0"
x:Name="DateSwitch"
IsToggled="{Binding DateFilterEnabled}" />
<Label Grid.Column="1"
Text="Date"
IsEnabled="{Binding DateFilterEnabled}"
VerticalOptions="Center" />
<Border Grid.Column="3"
Stroke="Transparent"
BackgroundColor="#555555"
StrokeShape="RoundRectangle 30"
HeightRequest="20"
WidthRequest="20"
Margin="10"
Padding="5"
HorizontalOptions="Start">
<Image Source="appinfo_icon.svg" />
<Border.GestureRecognizers>
<TapGestureRecognizer x:Name="DateInfoTapGesture"
Command="{Binding ShowDateFilterHelpCommand}" />
</Border.GestureRecognizers>
</Border>
</Grid>
<!-- Future-ish events filter -->
<Grid Grid.Row="1" ColumnDefinitions="auto,auto,auto,auto"
Margin="20,0,5,0"
ColumnSpacing="10"
IsEnabled="{Binding DateFilterEnabled}"
MaximumHeightRequest="40">
<controls:TextSwitch Grid.Column="0"
Text="Futurs"
Activated="{Binding FutureDateFilterEnabled}" />
<controls:TextSwitch Grid.Column="1"
Text="Semaine"
Activated="{Binding ThisWeekFilterEnabled}" />
<controls:TextSwitch Grid.Column="2"
Text="Mois"
Activated="{Binding ThisMonthFilterEnabled}" />
<controls:TextSwitch Grid.Column="3"
Text="Année"
Activated="{Binding ThisYearFilterEnabled}" />
</Grid>
<!-- Custom date events filtering -->
<Grid Grid.Row="3" ColumnDefinitions="*,*"
Margin="20,0,5,0"
ColumnSpacing="10"
IsEnabled="{Binding DateFilterEnabled}">
<controls:TextSwitch Grid.Column="0"
Text="Manuelle"
Activated="{Binding CustomDateFilterEnabled}" />
<Grid Grid.Column="1" RowDefinitions="*,*"
ColumnSpacing="10"
HorizontalOptions="End"
IsEnabled="{Binding CustomDateFilterEnabled}">
<Grid Grid.Row="0"
ColumnDefinitions="auto,*"
ColumnSpacing="10">
<Label Grid.Column="0"
Text="Début"
VerticalOptions="Center" />
<Border Grid.Column="1"
Stroke="Transparent"
StrokeShape="RoundRectangle 20"
MaximumHeightRequest="40"
BackgroundColor="Transparent"
HorizontalOptions="End">
<DatePicker VerticalOptions="Center"
HorizontalOptions="Center"
Margin="10,0"
Date="{Binding CustomStartDate}" />
</Border>
</Grid>
<Grid Grid.Row="1"
ColumnDefinitions="auto,*"
ColumnSpacing="10">
<Label Grid.Column="0"
Text="Fin"
VerticalOptions="Center" />
<Border Grid.Column="1"
Stroke="Transparent"
StrokeShape="RoundRectangle 20"
MaximumHeightRequest="40"
BackgroundColor="Transparent"
HorizontalOptions="End">
<DatePicker VerticalOptions="Center"
HorizontalOptions="Center"
Margin="10,0"
Date="{Binding CustomEndDate}" />
</Border>
</Grid>
</Grid>
</Grid>
</Grid>
</Border>The code-behind page is totally trivial (default implementation).
And here is a sample of what the ViewModel looks like:
public partial class EventListFilterViewModel : ObservableObject
{
#region Date Filter Properties
[ObservableProperty] private bool _dateFilterEnabled = true;
// Future filter, this is the default state of the query (reproduces the default website behavior)
[ObservableProperty] private bool _futureDateFilterEnabled = true;
// Past Filters
[ObservableProperty] private bool _thisWeekFilterEnabled = false;
[ObservableProperty] private bool _thisMonthFilterEnabled = false;
[ObservableProperty] private bool _thisYearFilterEnabled = false;
// Custom Date Filters
[ObservableProperty] private bool _customDateFilterEnabled = false;
[ObservableProperty] private DateTime _customStartDate = DateTime.Now.AddYears(-1);
[ObservableProperty] private DateTime _customEndDate = DateTime.Now;
partial void OnFutureDateFilterEnabledChanged(bool value)
{
if(value && ThisWeekFilterEnabled)
{
ThisWeekFilterEnabled = false;
}
if (value && ThisMonthFilterEnabled)
{
ThisMonthFilterEnabled = false;
}
if (value && ThisYearFilterEnabled)
{
ThisYearFilterEnabled = false;
}
else if(value && CustomDateFilterEnabled)
{
CustomDateFilterEnabled = false;
}
}
partial void OnThisWeekFilterEnabledChanged(bool value)
{
if (value && FutureDateFilterEnabled)
{
FutureDateFilterEnabled = false;
}
if (value && ThisMonthFilterEnabled)
{
ThisMonthFilterEnabled = false;
}
if (value && ThisYearFilterEnabled)
{
ThisYearFilterEnabled = false;
}
if (value && CustomDateFilterEnabled)
{
CustomDateFilterEnabled = false;
}
}
partial void OnThisMonthFilterEnabledChanged(bool value)
{
if (value && FutureDateFilterEnabled)
{
FutureDateFilterEnabled = false;
}
if (value && ThisWeekFilterEnabled)
{
ThisWeekFilterEnabled = false;
}
if (value && ThisYearFilterEnabled)
{
ThisYearFilterEnabled = false;
}
if (value && CustomDateFilterEnabled)
{
CustomDateFilterEnabled = false;
}
}
// ...
}As you may notice, the ViewModel overrides the CommunityToolkit-generated handlers and hooks up custom logic to update the ObservableProperties.
=> In the logic, you'll notice that;
- When you update one property state (say, FutureDateFilterEnabled), it'll exclude the other properties and revert them back to false.
This is meant to implement a mutually-exclusive pattern, where only a single visual state can remain.
Link to public reproduction project repository
No response
Version with bug
10.0.90
Is this a regression from previous behavior?
Yes, this used to work in .NET MAUI
Last version that worked well
10.0.80
Affected platforms
Android
Affected platform versions
No response
Did you find any workaround?
Remaining on 10.0.80 ... Or find a way to rewrite the logic in the control itself, to circumvent the UI Properties not being well-transferred.
Activity
Ahamed-Ali commentedon Jul 30, 2026
Based on the provided information, I have created a sample, but I am unable to reproduce the issue. Could you please provide a reproduction sample or modify the sample below to reproduce the issue? This would help us investigate the issue more quickly.
Screen.Recording.2026-07-30.at.6.23.05.PM.mov
Issue36942 (1).zip
bebenlebricolo commentedon Jul 31, 2026
Excellent, thanks @Ahamed-Ali .
I've put together a small bug repro repository and I managed to narrow the issue down to being triggered by a Border Shadow !
In the sample code I gave you earlier, the main Border was missing (as it is a modal popup page, I wanted a shadow around the main border and thought it was not relevant to the issue itself.)
Here in this screencast, you'll see that using Hot Reload (on Rider, but that should not affect the behavior), I could demonstrate that applying a shadow on the main border prevents proper UI event propagation/update.
Capture.video.du.2026-07-31.10-42-19.mp4
Here is the reproduction repository:
MauiBug-10.0.90-BorderShadow-BreaksUIUpdates-Issue36942
Note: maybe the Shadow behavior isn't the culprit here and it could be a combination of other issues, but at least I can reproduce the bug with a simple commented section, which is particularly handy 😄
Let me know if you managed to reproduce the issue yourself !
NafeelaNazhir commentedon Jul 31, 2026
This issue has been validated in Visual Studio Code 1.130.0 with .NET MAUI versions 10.0.80 and 10.0.90. It can be reproduced on the Android platform from 10.0.90 version
Screen.Recording.2026-07-31.at.2.36.21.PM.mov
Screen.Recording.2026-07-31.at.2.38.59.PM.mov
6 remaining items
[WIP] Fix Border with Shadow breaking descendant BackgroundColor upda…
[WIP] Fix Border with Shadow breaking descendant BackgroundColor upda…
MohammadHoutari commentedon Aug 13, 2026
Another manifestation of this 10.0.90 Android regression, from a shipped app — this one takes out a camera preview, and I think it argues for backporting #36988 to a 10.0.9x servicing release rather than waiting for SR10.
Symptom
A CameraX preview (
BarcodeScanning.Native.Maui3.0.6, which renders into aPreviewViewinImplementationMode.Compatible, i.e. aTextureView) hosted in a MAUI app on Android:PopupPopupPopupwhose rootBorderhasStrokeThickness="0"+Border.ShadowContentPage, no shadowMicrosoft.Maui.Controlswas the only package changed between working and broken. Reproduced twice — reverting to 10.0.80 restored the preview, re-upgrading to 10.0.90 broke it again. Device: Xiaomi, Android 15.Why I am posting it here
The white case is literally the pattern called out in #37279 and fixed by #36988 — a fully-transparent-stroke
Borderwith aShadow, with the affected content as a descendant:And the described mechanism — software-canvas fallback clearing Android descendant dirty flags before the hardware pass, so stale display lists replay — matches a frozen camera preview more exactly than it matches a janky list. A
TextureViewinvalidating 30 times a second is close to a worst case for "frequent descendant invalidations."One observation that may not fit
Replacing the wrapping
Borderwith a plainGrid— removing theShadow, the rounded-corner clip, and with them thePlatformWrapperViewentirely — did not restore the preview. The black and frozen-frame cases also occur with no shadow anywhere in the ancestor chain.So either the camera preview is a second, distinct regression in 10.0.90, or
PlatformWrapperViewis not the only invalidation path that #35623 affected. I would rather flag that honestly than assert a root cause I have not proven.Impact
There is currently no released MAUI version with the fix — 10.0.90 is still the newest 10.0.x on NuGet, and #36988 is milestoned for SR10. For apps whose core workflow is barcode scanning, 10.0.90 is simply not adoptable, and the only option is to stay on 10.0.80 and forgo everything else in the release.
If a backport of #36988 into a 10.0.9x servicing build is possible, it would unblock this class of app. I am happy to build a minimal repro (MAUI 10.0.90 + a TextureView-based camera preview, with and without a shadowed ancestor) if that would help triage.
[release/10.0.1xx-sr10] Integrate .NET MAUI 10.0.101 VS insertion pay…
bebenlebricolo commentedon Sep 4, 2026
Tested with 10.0.100 package version and I confirm this is fixed (at least for my use-case, this is a win. Thanks guys !)