[Issue-Resolver] Add UnderlineColor property to InputView controls (skills)#33309
[Issue-Resolver] Add UnderlineColor property to InputView controls (skills)#33309kubaflo wants to merge 4 commits into
Conversation
Introduces a new UnderlineColor bindable property to InputView, ITextInput, Entry, and Editor, allowing customization or removal of the underline on Android and iOS. Updates platform handlers and extensions to support the property, adds mapping logic, and includes new test cases and snapshots to verify correct behavior across platforms. On Windows, the property is a no-op as TextBox uses borders.
Review Feedback: PR #33309 - Add UnderlineColor property to InputView controls🤖 Copilot Session SummaryThis review was conducted through a detailed analysis session:
RecommendationSummary: This is a well-implemented and highly-requested feature with comprehensive testing. However, there are architectural concerns about the iOS implementation that should be addressed, and the property type pattern needs clarification in documentation. 📋 Full Review DetailsFeature ContextIssue #7906 (opened June 2022):
This PR addresses the underline customization portion of the request by adding a new Implementation OverviewAPI DesignNew Property: // ITextInput.cs (Core interface)
Color? UnderlineColor { get; }
// InputView.cs (Controls layer)
public Color UnderlineColor
{
get { return (Color)GetValue(UnderlineColorProperty); }
set { SetValue(UnderlineColorProperty, value); }
}Platform Implementations:
|
| Scenario | Risk Level | Why It Matters |
|---|---|---|
| Null → Color → Null transitions | Medium | Verifies cleanup and default restoration |
| Rapid property changes | Low | Could expose layer/memory issues on iOS |
| Orientation change (iOS) | Medium | Tests LayoutSubviews layer repositioning |
| Custom backgrounds (Android) | Medium | Verifies no side effects from BackgroundTintList |
| Memory/performance | Low | Long-term stability for production apps |
Recommendation:
- ✅ Current tests are sufficient for initial approval
- 📝 Document these as future test scenarios
⚠️ Consider adding null transition test before merge
✅ Strengths
1. Excellent API Design
- ✅ Consistent naming: Follows MAUI conventions
- ✅ Comprehensive documentation: XML docs explain platform-specific behavior
- ✅ Flexible: Supports null (default), transparent (hide), and custom colors
2. Proper Platform Abstraction
- ✅ Native approach on Android: Uses Material Design APIs
- ✅ Custom implementation on iOS: Necessary since iOS doesn't have native underlines
- ✅ Appropriate no-op on Windows: Documented clearly
3. Handler Integration
- ✅ Correct mapper entries: Added to both Entry and Editor handlers
- ✅ All platforms covered: Android, iOS, MacCatalyst, Windows, Standard, Tizen
4. PublicAPI Management
- ✅ All PublicAPI.Unshipped.txt files updated: 14 files across all TFMs
- ✅ Correct signatures: Matches the implementation
5. Test Quality
- ✅ Real device tests: Uses Appium with screenshot verification
- ✅ Multiple platforms: iOS and Android snapshots
- ✅ Comprehensive test page: 6 scenarios covering key use cases
- ✅ VisualStateManager integration: Tests focus state changes
6. VisualStateManager Support
The implementation automatically supports VSM without any special code:
<Entry UnderlineColor="Blue">
<VisualStateManager.VisualStateGroups>
<VisualState x:Name="Focused">
<Setter Property="UnderlineColor" Value="Red"/>
</VisualState>
</VisualStateManager.VisualStateGroups>
</Entry>Code Quality
Positive Observations
- ✅ Clean code: Well-organized, readable
- ✅ Good comments: Implementation notes explain platform choices
- ✅ Defensive programming: Null checks in place
- ✅ Reusable helpers:
GetUnderlineColorStateList,UpdateUnderlineLayerare separate methods
Minor Style Suggestions
- iOS Extensions: Consider extracting common layer logic to avoid duplication between
TextFieldExtensionsandTextViewExtensions - Android: The
GetUnderlineColorStateListmethod could be inlined (only one line) or made more sophisticated if you want to support different states (focused, disabled, etc.)
Architectural Questions
1. Border vs Underline Scope
Original issue title: "option to disable borders and underline"
This PR: Only addresses underline customization
Question: Is there a plan to also add BorderColor or ShowBorder properties?
Recommendation: This PR is complete for its scope (underline). Border customization could be a separate feature.
2. Windows Platform - Should It Be a No-Op?
Current behavior: No-op on Windows (documented in remarks)
Consideration: Windows TextBox uses borders, not underlines. Should this property:
- Option A: Stay no-op (current) ✅
- Option B: Control border color instead?
- Option C: Add a separate
BorderColorproperty for all platforms?
Recommendation: Keep as no-op for this PR. If border control is needed, it should be a separate, properly-designed API.
Testing Recommendations
Before Merge
- Test null → Color → null transition (verify layer cleanup on iOS)
- Test with custom EditText backgrounds on Android
- Verify no memory leaks with repeated view creation/destruction
Post-Merge (Future)
- Performance testing with hundreds of Entry/Editor controls
- Accessibility testing (does underline color affect screen readers?)
- Interaction with other properties (Background, Border, etc.)
Documentation Needs
User-Facing Documentation
This feature should be documented in:
- Migration guide (for .NET 11 when this ships)
- Entry/Editor control reference: https://learn.microsoft.com/dotnet/maui/user-interface/controls/entry
- Styling guide: Include examples of hiding underlines for cleaner UI
Sample Code for Docs
<!-- Hide underline -->
<Entry UnderlineColor="Transparent" />
<!-- Custom color -->
<Entry UnderlineColor="Blue" />
<!-- Dynamic with VisualStateManager -->
<Entry UnderlineColor="Gray">
<VisualStateManager.VisualStateGroups>
<VisualState x:Name="Focused">
<Setter Property="UnderlineColor" Value="Blue"/>
</VisualState>
</VisualStateManager.VisualStateGroups>
</Entry>Comparison with Alternative Approaches
Alternative 1: Boolean ShowUnderline Property
public bool ShowUnderline { get; set; } = true;Pros: Simpler API, less ambiguous
Cons: Doesn't allow color customization, less flexible
Verdict: Chosen approach (Color?) is better ✅
Alternative 2: Separate Properties
public bool ShowUnderline { get; set; } = true;
public Color UnderlineColor { get; set; }Pros: More explicit control
Cons: Two properties to manage, more complex
Verdict: Chosen approach is more elegant ✅
Alternative 3: Custom Underline Object
public Underline? Underline { get; set; }
class Underline
{
public Color Color { get; set; }
public double Thickness { get; set; }
}Pros: Future-proof for additional underline properties
Cons: Over-engineered for current need
Verdict: Chosen approach is appropriately scoped ✅
Fix Complexity Analysis
| Aspect | Complexity | Lines Changed | Notes |
|---|---|---|---|
| Core API | Low | ~15 | Interface + BindableProperty |
| Controls Layer | Low | ~20 | Property + explicit interface impl |
| Android Implementation | Low | ~25 | Native Material Design API |
| iOS Implementation | Medium | ~130 | Custom CALayer + lifecycle management |
| Handler Integration | Low | ~30 | Mapper entries across platforms |
| PublicAPI | Trivial | ~40 | Bulk file updates |
| Tests | Medium | ~140 | XAML page + NUnit tests + snapshots |
| Total | Medium | ~407 | Well-distributed across layers |
Overall Assessment: Appropriate complexity for a cross-platform UI feature. iOS implementation is the most complex due to lack of native underline support.
Approval Checklist
Must Fix Before Approval
- iOS Memory Management: Add explicit
Dispose()call inRemoveUnderlineLayer - Property Nullability: Add nullable annotation to public property:
public Color? UnderlineColor
Should Address (Recommended)
- iOS Performance: Add early exit in
UpdateUnderlineLayerFrameif no layers exist - Test Coverage: Add null transition test (null → color → null)
Nice to Have (Optional)
- Extract common iOS layer logic to reduce duplication between TextField and TextView extensions
- Add performance test for many Entry/Editor controls
- Document interaction with custom backgrounds (Android)
Already Excellent ✅
- Code solves the stated problem
- Appropriate test coverage (2 comprehensive UI tests)
- Follows existing MAUI patterns (Color property handling)
- Platform-appropriate implementations
- No security concerns
- PublicAPI files updated correctly
- Handler mappings complete
- VisualStateManager support works automatically
Final Verdict
This is a high-quality implementation of a long-requested feature. The code is clean, well-tested, and follows MAUI conventions. The concerns raised are mostly about optimization and best practices rather than correctness.
Primary Issues:
- iOS memory management (layer disposal)
- Property nullability documentation
Recommendation: Request Changes to address memory management and nullability, then approve. This is very close to merge-ready.
For the PR Author
Great work on this PR! You've implemented a feature that the community has been requesting for 2.5 years. The implementation is solid and shows good understanding of both MAUI architecture and platform-specific concerns.
What I particularly liked:
- Comprehensive test coverage with screenshot verification
- Excellent documentation in XML comments
- Clean separation of concerns across layers
- Proper handling of all platforms (including Windows no-op)
Small improvements needed:
- Add explicit disposal in iOS layer cleanup
- Update property signature to
Color?for clarity
Once these are addressed, this should be ready to merge!
- Add explicit Dispose() call in RemoveUnderlineLayer for iOS memory management - Add early exit optimization in UpdateUnderlineLayerFrame to avoid unnecessary layer searches Note: Nullable annotation (Color?) was suggested but breaks build in non-nullable context. The existing pattern (non-nullable Color with null default) matches other Color properties in MAUI (PlaceholderColor, TextColor) and is consistent with the codebase.
Review Feedback: PR #33309 - UnderlineColor Property for Entry and Editor🤖 Copilot Session SummaryThis review was conducted through an interactive deep-dive session:
RecommendationSummary: The Android implementation has a critical bug that will break Entry/Editor controls when both 🚨 CRITICAL REGRESSION FOUNDAndroid: BackgroundColor + UnderlineColor ConflictSeverity: HIGH Issue: The PR's Android implementation uses Root CauseOn Android, Entry/Editor backgrounds are managed by
The PR's editText.BackgroundTintList = ColorStateList.ValueOf(androidColor);Problem: Reproduction<Entry Text="Should have red background and blue underline"
Background="Red"
UnderlineColor="Blue" />Expected: Red background fill with blue underline Impact
Why Not Caught by PR TestsThe PR's tests (
Alternative Android Implementation (Recommended)Option 1: Custom Drawable Approach (Cleanest)Instead of using public static void UpdateUnderlineColor(this EditText editText, ITextInput textInput)
{
var underlineColor = textInput.UnderlineColor;
if (underlineColor == null)
{
// Reset to default - rebuild the background
UpdateBackground(editText, textInput as IView);
return;
}
// Get or create MauiLayerDrawable with custom underline color
var context = editText.Context;
if (context == null) return;
// Clone the default material drawable and tint ONLY it
var underlineDrawable = ContextCompat.GetDrawable(context, Resource.Drawable.abc_edit_text_material)?.Mutate();
if (underlineDrawable != null)
{
underlineDrawable.SetColorFilter(underlineColor.ToPlatform(), FilterMode.SrcIn);
}
// Get user's background if any
var existingBackground = editText.Background;
var userBackground = (existingBackground is MauiLayerDrawable layerDrawable && layerDrawable.NumberOfLayers > 0)
? layerDrawable.GetDrawable(0)
: null;
// Create new layer with user background (if any) + tinted underline
editText.Background = userBackground != null
? new MauiLayerDrawable(userBackground, underlineDrawable)
: new MauiLayerDrawable(underlineDrawable);
}Pros:
Cons:
Option 2: Direct Layer Manipulation (Simpler)public static void UpdateUnderlineColor(this EditText editText, ITextInput textInput)
{
var underlineColor = textInput.UnderlineColor;
var background = editText.Background;
if (background is MauiLayerDrawable layerDrawable && layerDrawable.NumberOfLayers >= 2)
{
// The underline is typically the top layer
var underlineLayer = layerDrawable.GetDrawable(layerDrawable.NumberOfLayers - 1);
if (underlineColor == null)
{
underlineLayer.ClearColorFilter();
}
else
{
underlineLayer.SetColorFilter(underlineColor.ToPlatform(), FilterMode.SrcIn);
}
}
}Pros:
Cons:
iOS Implementation ReviewStrengths ✅
Potential Optimizations (Non-Critical)Performance with Many Entry Controls: The current internal static void UpdateUnderlineLayerFrame(UIView view)
{
// Early exit if no layers exist (most common case)
if (view.Layer.Sublayers == null || view.Layer.Sublayers.Length == 0)
return;
const string layerName = "MauiTextInputUnderlineLayer";
var underlineLayer = view.Layer.Sublayers.FirstOrDefault(l => l.Name == layerName);
if (underlineLayer != null)
{
var bounds = view.Bounds;
underlineLayer.Frame = new CGRect(0, bounds.Height - 2, bounds.Width, 2);
}
}Optional optimization (caching layer reference): // In MauiTextField/MauiTextView
private WeakReference<CALayer>? _underlineLayerRef;
public override void LayoutSubviews()
{
base.LayoutSubviews();
// Fast path: Use cached reference
if (_underlineLayerRef?.TryGetTarget(out var layer) == true)
{
var bounds = Bounds;
layer.Frame = new CGRect(0, bounds.Height - 2, bounds.Width, 2);
}
else
{
// Slow path: Search for layer (handles add/remove cases)
TextFieldExtensions.UpdateUnderlineLayerFrame(this);
// Cache it if found
var underlineLayer = Layer.Sublayers?.FirstOrDefault(l => l.Name == "MauiTextInputUnderlineLayer");
if (underlineLayer != null)
_underlineLayerRef = new WeakReference<CALayer>(underlineLayer);
}
}Note: This is premature optimization. Current code is clean and performant enough for typical scenarios. Test Coverage Analysis✅ Already Covered by PR's Tests
|
- Changed from BackgroundTintList (tints entire background) to SetColorFilter (targets only underline layer) - Added regression test: BackgroundAndUnderlineColorWorkTogether - Updated Android snapshots to reflect correct implementation - Addresses critical regression identified in PR review dotnet#33309
- Changed from BackgroundTintList (tints entire background) to SetColorFilter (targets only underline layer) - Added regression test: BackgroundAndUnderlineColorWorkTogether - Updated Android snapshots to reflect correct implementation - Addresses critical regression identified in PR review dotnet#33309
Review Feedback: PR #33309 - Add UnderlineColor Property🤖 Copilot Session SummaryThis review was conducted through a detailed analysis session:
Recommendation✅ Approve with Minor Suggestions Summary: This is an exceptionally well-implemented feature PR that addresses a highly-requested community need (67 👍 reactions, 2+ year old issue). The implementation is clean, comprehensive, and includes excellent test coverage with proper regression testing. Ready to merge with minor suggestions for future consideration. 📋 Full Review DetailsStrengths of This PR1. ✅ Excellent API DesignThe API is well-designed and consistent with MAUI patterns: public Color? UnderlineColor { get; set; }Why this is good:
Comparison to alternatives:
2. ✅ Comprehensive Cross-Platform Implementation
Android Implementation Highlights: // Smart detection of layered vs simple drawables
if (background is MauiLayerDrawable layerDrawable && layerDrawable.NumberOfLayers >= 2)
{
var underlineLayer = layerDrawable.GetDrawable(layerDrawable.NumberOfLayers - 1);
underlineLayer?.SetColorFilter(underlineColor.ToPlatform(), FilterMode.SrcIn);
}
iOS Implementation Highlights: // CALayer approach - clean and composable
var underlineLayer = new CoreAnimation.CALayer { Name = "MauiTextInputUnderlineLayer" };
view.Layer.AddSublayer(underlineLayer);
3. ✅ Excellent Test CoverageThe test coverage is exceptional for a feature PR: Test Page Design (Issue7906.xaml):
NUnit Tests (Issue7906.cs):
Baseline Screenshots:
4. ✅ Addresses Long-Standing Community NeedFrom issue #7906 (opened June 2022):
This PR provides the official solution that users have been implementing via custom handlers for 2+ years. 5. ✅ Clean Integration with Existing Features
Areas for Future Consideration (Not Blocking)1. 💡 Android: Potential Race Condition with Background ChangesCurrent Code: public static void UpdateUnderlineColor(this EditText editText, ITextInput textInput)
{
var background = editText.Background;
if (background is MauiLayerDrawable layerDrawable && layerDrawable.NumberOfLayers >= 2)
{
var underlineLayer = layerDrawable.GetDrawable(layerDrawable.NumberOfLayers - 1);
underlineLayer?.SetColorFilter(underlineColor.ToPlatform(), FilterMode.SrcIn);
}
}Potential Issue: Scenario: entry.UnderlineColor = Colors.Blue; // Sets color filter on current background
entry.Background = new SolidColorBrush(Colors.Red); // NEW background, no color filter
// Result: Blue underline is lostTest Case #7 Doesn't Catch This because Background is set before UnderlineColor in XAML (evaluation order matters). Suggested Solution (Future PR): public static void MapBackground(IEntryHandler handler, IEntry entry)
{
handler.PlatformView?.UpdateBackground(entry);
handler.PlatformView?.UpdateUnderlineColor(entry); // Re-apply underline
}Action: Not blocking this PR. Consider as follow-up enhancement if users report the issue. 2. 💡 iOS: Performance - Sublayers Enumeration on Every LayoutCurrent Code: internal static void UpdateUnderlineLayerFrame(UIView view)
{
if (view.Layer.Sublayers == null || view.Layer.Sublayers.Length == 0)
return;
var underlineLayer = view.Layer.Sublayers.FirstOrDefault(l => l.Name == layerName);
// ...
}Minor Optimization Opportunity: Suggested Optimization: private CALayer? _underlineLayer;
public void SetUnderlineLayer(CALayer? layer)
{
_underlineLayer = layer;
}
public override void LayoutSubviews()
{
base.LayoutSubviews();
if (_underlineLayer != null)
{
var bounds = Bounds;
_underlineLayer.Frame = new CGRect(0, bounds.Height - 2, bounds.Width, 2);
}
}Action: Not a performance concern for most apps. Consider as micro-optimization if profiling shows it's an issue. 3. 📝 Documentation: Clarify Android Behavior with Custom BackgroundsCurrent XML Comments: /// On Android, this controls the Material Design underline color.Clarification Needed:
Suggested Documentation Enhancement: /// On Android, this controls the Material Design underline color.
/// When used with custom backgrounds (via Background property), only the underline
/// layer is tinted, preserving the user's background drawable.
/// If no custom background exists, the entire background drawable is tinted.Action: Minor doc improvement for next doc update cycle. 4. ❓ Question: Should This Be ITextStyle Instead of ITextInput?Current: Consideration: Is underline a "style" property (like TextColor) or an "input behavior" property? Other style properties:
Decision: Keeping it in
Action: No change needed. Current placement is appropriate. Regression Risk Assessment✅ Low Risk - This is a purely additive feature:
Potential Regressions Tested:
Not Tested (Future Risk):
Final Verdict✅ APPROVE - Merge this PR Reasoning:
Recommendation to Team:
Approval Checklist
For PR Author (@kubaflo)Excellent work on this PR! 🎉 The implementation quality is very high:
The suggestions above are not blockers - they're future considerations if edge cases arise. Suggested Next Steps:
Great contribution to the MAUI community! 🚀 References
|
Modified MapBackground to also update the underline color of the Entry control on Android, ensuring visual consistency when the background changes.
There was a problem hiding this comment.
Pull request overview
This PR adds an UnderlineColor property to Entry and Editor controls (via the InputView base class), addressing issue #7906. The implementation provides a way to customize or hide the underline color on Android (Material Design) and iOS, with proper lifecycle management and comprehensive test coverage.
Key Changes
- Added
Color? UnderlineColorproperty toITextInputinterface andInputViewclass - Implemented platform-specific underline rendering for Android (Material Design tint) and iOS (CALayer)
- Added lifecycle management for iOS to handle layout changes
- Included comprehensive UI tests with screenshot validation
Reviewed changes
Copilot reviewed 33 out of 45 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
src/Core/src/Core/ITextInput.cs |
Added nullable UnderlineColor property to core interface |
src/Controls/src/Core/InputView/InputView.cs |
Added UnderlineColorProperty bindable property (not shown in diff but referenced) |
src/Core/src/Handlers/Entry/EntryHandler.cs |
Added mapper entry for UnderlineColor |
src/Core/src/Handlers/Entry/EntryHandler.Android.cs |
Android implementation calling UpdateUnderlineColor |
src/Core/src/Handlers/Entry/EntryHandler.iOS.cs |
iOS implementation calling UpdateUnderlineColor |
src/Core/src/Handlers/Entry/EntryHandler.Windows.cs |
Windows no-op implementation |
src/Core/src/Handlers/Entry/EntryHandler.Standard.cs |
Standard no-op implementation |
src/Core/src/Handlers/Editor/EditorHandler.cs |
Added mapper entry for UnderlineColor |
src/Core/src/Handlers/Editor/EditorHandler.Android.cs |
Android implementation calling UpdateUnderlineColor |
src/Core/src/Handlers/Editor/EditorHandler.iOS.cs |
iOS implementation calling UpdateUnderlineColor |
src/Core/src/Handlers/Editor/EditorHandler.Windows.cs |
Windows no-op implementation |
src/Core/src/Handlers/Editor/EditorHandler.Standard.cs |
Standard no-op implementation |
src/Core/src/Platform/Android/EditTextExtensions.cs |
Android Material Design underline implementation using ColorFilter |
src/Core/src/Platform/iOS/TextFieldExtensions.cs |
iOS CALayer-based underline for UITextField |
src/Core/src/Platform/iOS/TextViewExtensions.cs |
iOS CALayer-based underline for UITextView |
src/Core/src/Platform/iOS/MauiTextField.cs |
Added LayoutSubviews override for underline repositioning |
src/Core/src/Platform/iOS/MauiTextView.cs |
Added LayoutSubviews override for underline repositioning |
| PublicAPI files (13 files) | Added API entries for new property and handler methods |
src/Controls/tests/TestCases.HostApp/Issues/Issue7906.xaml.cs |
Test page code-behind with Issue attribute |
src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue7906.cs |
NUnit tests with screenshot validation |
| Snapshot files (8 files) | Baseline screenshots for iOS and Android |
PR Description - UnderlineColor Property for Entry and Editor
Fixes #7906
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!
Summary
This PR adds the
UnderlineColorproperty toEntryandEditorcontrols, allowing developers to customize or hide the underline color on Android (Material Design) and iOS. This addresses a long-standing feature request to provide more control over text input styling.Quick verification:
📋 Click to expand full PR details
What's New
Developers can now:
entry.UnderlineColor = Colors.Blue;entry.UnderlineColor = Colors.Transparent;entry.UnderlineColor = null;Implementation Details
Core API Layer
ITextInput.cs- Added nullableColor? UnderlineColor { get; }property to the core interface.InputView.cs- Added bindable property:Handler Layer
Entry and Editor Handlers - Added mapper entries:
Platform Implementations
Android
Uses Material Design's
BackgroundTintListfor native underline color control:iOS
Creates a custom
CALayerpositioned at the bottom of the view:iOS Lifecycle Management - Override
LayoutSubviews()to reposition underline on layout changes:This ensures the underline:
Windows
No-op implementation (TextBox uses borders, not underlines):
Testing
Test Coverage
Test Page:
TestCases.HostApp/Issues/Issue7906.xamlNUnit Tests:
TestCases.Shared.Tests/Tests/Issues/Issue7906.csTest 1:
UnderlineColorPropertyWorksTest 2:
UnderlineColorChangesOnFocusTest Results
Baseline Snapshots: 8 files total (4 iOS + 4 Android)
snapshots/ios/UnderlineColorPropertyWorks.pngsnapshots/ios/UnfocusedState.pngsnapshots/ios/FocusedState.pngsnapshots/ios/ReturnToUnfocused.pngsnapshots/android-notch-36/UnderlineColorPropertyWorks.pngsnapshots/android-notch-36/UnfocusedState.pngsnapshots/android-notch-36/FocusedState.pngsnapshots/android-notch-36/ReturnToUnfocused.pngBefore/After
Before (Issue #7906):
After (This PR):
UnderlineColorproperty available on Entry and Editornullrestores platform defaultsFiles Changed
Core API (2 files + 6 PublicAPI files)
src/Core/src/Core/ITextInput.cs- AddedUnderlineColorpropertysrc/Core/src/PublicAPI/net/PublicAPI.Unshipped.txt- Added API entriessrc/Core/src/PublicAPI/netstandard/PublicAPI.Unshipped.txt- Added API entriessrc/Core/src/PublicAPI/net-android/PublicAPI.Unshipped.txt- Added handler mappingssrc/Core/src/PublicAPI/net-ios/PublicAPI.Unshipped.txt- Added handler mappings + LayoutSubviewssrc/Core/src/PublicAPI/net-maccatalyst/PublicAPI.Unshipped.txt- Added handler mappings + LayoutSubviewssrc/Core/src/PublicAPI/net-windows/PublicAPI.Unshipped.txt- Added handler mappingsControls Layer (1 file + 7 PublicAPI files)
src/Controls/src/Core/InputView/InputView.cs- Added bindable propertysrc/Controls/src/Core/PublicAPI/net/PublicAPI.Unshipped.txt- Added propertysrc/Controls/src/Core/PublicAPI/netstandard/PublicAPI.Unshipped.txt- Added propertysrc/Controls/src/Core/PublicAPI/net-android/PublicAPI.Unshipped.txt- Added propertysrc/Controls/src/Core/PublicAPI/net-ios/PublicAPI.Unshipped.txt- Added propertysrc/Controls/src/Core/PublicAPI/net-maccatalyst/PublicAPI.Unshipped.txt- Added propertysrc/Controls/src/Core/PublicAPI/net-tizen/PublicAPI.Unshipped.txt- Added propertysrc/Controls/src/Core/PublicAPI/net-windows/PublicAPI.Unshipped.txt- Added propertyHandler Layer (10 files)
src/Core/src/Handlers/Entry/EntryHandler.cs- Added mappersrc/Core/src/Handlers/Entry/EntryHandler.Android.cs- Android implementationsrc/Core/src/Handlers/Entry/EntryHandler.iOS.cs- iOS implementationsrc/Core/src/Handlers/Entry/EntryHandler.Windows.cs- Windows no-opsrc/Core/src/Handlers/Entry/EntryHandler.Standard.cs- Standard no-opsrc/Core/src/Handlers/Editor/EditorHandler.cs- Added mappersrc/Core/src/Handlers/Editor/EditorHandler.Android.cs- Android implementationsrc/Core/src/Handlers/Editor/EditorHandler.iOS.cs- iOS implementationsrc/Core/src/Handlers/Editor/EditorHandler.Windows.cs- Windows no-opsrc/Core/src/Handlers/Editor/EditorHandler.Standard.cs- Standard no-opPlatform Extensions (5 files)
src/Core/src/Platform/Android/EditTextExtensions.cs- Material Design underlinesrc/Core/src/Platform/iOS/TextFieldExtensions.cs- CALayer underline for UITextFieldsrc/Core/src/Platform/iOS/TextViewExtensions.cs- CALayer underline for UITextViewsrc/Core/src/Platform/iOS/MauiTextField.cs- LayoutSubviews overridesrc/Core/src/Platform/iOS/MauiTextView.cs- LayoutSubviews overrideTest Infrastructure (11 files)
src/Controls/tests/TestCases.HostApp/Issues/Issue7906.xaml- Test pagesrc/Controls/tests/TestCases.HostApp/Issues/Issue7906.xaml.cs- Test page code-behindsrc/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue7906.cs- NUnit testssrc/Controls/tests/TestCases.iOS.Tests/snapshots/ios/UnderlineColorPropertyWorks.pngsrc/Controls/tests/TestCases.iOS.Tests/snapshots/ios/UnfocusedState.pngsrc/Controls/tests/TestCases.iOS.Tests/snapshots/ios/FocusedState.pngsrc/Controls/tests/TestCases.iOS.Tests/snapshots/ios/ReturnToUnfocused.pngsrc/Controls/tests/TestCases.Android.Tests/snapshots/android-notch-36/UnderlineColorPropertyWorks.pngsrc/Controls/tests/TestCases.Android.Tests/snapshots/android-notch-36/UnfocusedState.pngsrc/Controls/tests/TestCases.Android.Tests/snapshots/android-notch-36/FocusedState.pngsrc/Controls/tests/TestCases.Android.Tests/snapshots/android-notch-36/ReturnToUnfocused.pngTotal: 30 files modified/added
Edge Cases Tested
✅ Null handling - Setting to null restores platform defaults
✅ Transparent color - Effectively hides the underline
✅ VisualStateManager integration - Focus state changes work correctly
✅ iOS lifecycle - Underline repositions on layout changes, visible always
✅ Android Material Design - Uses native tint mechanism
✅ Multiple platforms - Tested on both iOS and Android
Breaking Changes
None. This is a purely additive feature.
Migration Guide
Not applicable (new feature, no migration needed).
Example Usage
Related Issues/PRs
Reviewer Notes
BackgroundTintList