Skip to content

Conversation

@StephaneDelcroix
Copy link
Contributor

Note

Are you waiting for the changes in this PR to be merged?
It would be very helpful if you could test the resulting artifacts from this PR and let us know in a comment if this change resolves your issue. Thank you!

Description of Change

This fixes issue #33203 where implicit styles using BasedOn with keyed styles stopped working in 10.0.20.

Root Cause

The regression was introduced by PR #32711 which fixed #9648 (ApplyToDerivedTypes not working for implicit styles). That fix created wrapper styles to merge multiple applicable implicit styles, but in doing so it replaced the original BasedOn chain with a new one, losing the connection to keyed styles that defined the actual property values.

The Fix

Instead of creating wrapper styles that break BasedOn chains, we now store the list of applicable implicit styles and apply them sequentially during Apply(). This preserves each style's BasedOn chain intact while still supporting the ApplyToDerivedTypes functionality from #9648.

Test Results

  • ✅ All 6 tests for ApplyToDerivedTypes not working for implicit styles #9648 (ApplyToDerivedTypes fix) still pass
  • ✅ All 1776 XAML unit tests pass (8 skipped, 0 failed)
  • ✅ All 164 Style-related Controls.Core unit tests pass
  • ✅ User's reproduction scenario (keyed style with BasedOn) now works correctly

Issues Fixed

Fixes #33203

This fixes issue #33203 where implicit styles using BasedOn with keyed styles
stopped working in 10.0.20. The regression was introduced by PR #32711 which
fixed #9648 (ApplyToDerivedTypes not working for implicit styles).

The problem was that when merging multiple applicable implicit styles, the
code created wrapper styles that replaced the original BasedOn chain, losing
the connection to keyed styles that defined the actual property values.

The fix changes the approach: instead of creating wrapper styles that break
BasedOn chains, we now store the list of applicable implicit styles and apply
them sequentially during Apply(). This preserves each style's BasedOn chain
intact while still supporting the ApplyToDerivedTypes functionality from #9648.

Fixes #33203
Copilot AI review requested due to automatic review settings December 18, 2025 16:08
@StephaneDelcroix StephaneDelcroix added this to the .NET 10.0 SR3 milestone Dec 18, 2025
@StephaneDelcroix StephaneDelcroix added t/bug Something isn't working area-xaml XAML, CSS, Triggers, Behaviors i/regression This issue described a confirmed regression on a currently supported version labels Dec 18, 2025
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes a regression in .NET MAUI 10.0.20 where implicit styles using BasedOn chains with keyed styles stopped working. The issue was introduced by PR #32711 which fixed ApplyToDerivedTypes functionality.

Key Changes

  • Changed merging strategy: Instead of creating wrapper styles that broke BasedOn chains, the fix now stores multiple applicable implicit styles in a list and applies them sequentially
  • Preserved BasedOn chains: Each style's BasedOn chain remains intact, ensuring property values from keyed styles are properly resolved
  • Maintained ApplyToDerivedTypes support: The fix continues to support multiple implicit styles from the type hierarchy while fixing the regression

Comment on lines 111 to 127
// Apply implicit styles from most base to most derived
// This ensures derived styles override base styles for conflicting properties
if (_applicableImplicitStyles != null && _applicableImplicitStyles.Count > 0)
{
// Apply in reverse order (most base first, most derived last)
// so derived styles override base styles
for (int i = _applicableImplicitStyles.Count - 1; i >= 0; i--)
{
//NOTE specificity could be more fine grained (using distance)
((IStyle)_applicableImplicitStyles[i]).Apply(bindable, new SetterSpecificity(SetterSpecificity.StyleImplicit, 0, 0, 0));
}
}
else
{
//NOTE specificity could be more fine grained (using distance)
ImplicitStyle?.Apply(bindable, new SetterSpecificity(SetterSpecificity.StyleImplicit, 0, 0, 0));
}
Copy link

Copilot AI Dec 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The logic for applying and unapplying multiple implicit styles is duplicated across multiple methods (Apply() at lines 113-127, UnApply() at lines 145-155, and SetStyle() at lines 254-264 and 275-286). Consider extracting this logic into private helper methods like ApplyImplicitStyles(BindableObject target) and UnApplyImplicitStyles(BindableObject target) to eliminate duplication and ensure consistency. This would improve maintainability and reduce the risk of introducing bugs when updating the style application logic in the future.

Copilot uses AI. Check for mistakes.
Comment on lines +202 to +204
// Set ImplicitStyle to the most derived style for compatibility
// (some code may check if ImplicitStyle is set)
ImplicitStyle = applicableStyles[0];
Copy link

Copilot AI Dec 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Setting ImplicitStyle to the most derived style (applicableStyles[0]) when multiple applicable styles exist may lead to unexpected behavior or confusion. Code that checks if ImplicitStyle is set may not realize there are multiple styles being applied. Consider either:

  1. Setting ImplicitStyle to null when multiple styles are present to make it clear that the _applicableImplicitStyles list should be used instead
  2. Adding a property or method to indicate when multiple implicit styles are active
    This would make the multi-style state more explicit and prevent potential misuse of the ImplicitStyle property.
Suggested change
// Set ImplicitStyle to the most derived style for compatibility
// (some code may check if ImplicitStyle is set)
ImplicitStyle = applicableStyles[0];
// When multiple implicit styles are active, leave ImplicitStyle null
// so callers know to consult _applicableImplicitStyles instead.
ImplicitStyle = null;

Copilot uses AI. Check for mistakes.
@StephaneDelcroix StephaneDelcroix marked this pull request as draft December 18, 2025 16:22
Tests verify that:
1. Implicit styles with BasedOn to keyed styles work correctly
2. Derived implicit styles properly override base styles' properties
jfversluis
jfversluis previously approved these changes Dec 19, 2025
When a base style uses AppThemeBinding for a property and a derived style
overrides that property with a static value, the AppThemeBinding would
re-apply when theme changes or resources propagate, overwriting the
derived style's value.

Changes:
- AppThemeBinding.Apply(fromTarget): Skip re-apply when value is set from target
- AppThemeBinding.ApplyCore(): Check if current value was set by this binding
  before re-applying (using IsValueFromThisBinding helper)
- MergedStyle: Apply graduated specificities for multiple implicit styles

Added unit test Maui33203AppTheme to verify derived style setters override
base style's AppThemeBinding in both Light and Dark modes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area-xaml XAML, CSS, Triggers, Behaviors i/regression This issue described a confirmed regression on a currently supported version t/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

10.0.20 breaks implicit styles ApplyToDerivedTypes not working for implicit styles

4 participants