From 946931bed94b1aa9b8b32fe1b3c61826e087e949 Mon Sep 17 00:00:00 2001 From: Mohammad Hossein Rastegarinia Date: Wed, 19 Nov 2025 11:46:03 +0000 Subject: [PATCH 01/10] replace Header with PlaceholderText for Title property of Picker on Windows (#32723) --- src/Core/src/Platform/Windows/PickerExtensions.cs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/Core/src/Platform/Windows/PickerExtensions.cs b/src/Core/src/Platform/Windows/PickerExtensions.cs index 30f33ec854df..95468e0c3e1c 100644 --- a/src/Core/src/Platform/Windows/PickerExtensions.cs +++ b/src/Core/src/Platform/Windows/PickerExtensions.cs @@ -9,11 +9,7 @@ public static class PickerExtensions { public static void UpdateTitle(this ComboBox nativeComboBox, IPicker picker) { - nativeComboBox.Header = string.IsNullOrEmpty(picker.Title) ? null : picker; - - nativeComboBox.HeaderTemplate = string.IsNullOrEmpty(picker.Title) ? null : - (UI.Xaml.DataTemplate)UI.Xaml.Application.Current.Resources["ComboBoxHeader"]; - + nativeComboBox.PlaceholderText = picker.Title ?? string.Empty; } public static void UpdateBackground(this ComboBox nativeComboBox, IPicker picker) From 95cffd0fb2bcc9c8f48532be53c57db5f7de9d1d Mon Sep 17 00:00:00 2001 From: Mohammad Hossein Rastegarinia Date: Sun, 19 Apr 2026 17:56:20 +0000 Subject: [PATCH 02/10] add UI Tests --- .../Elements/Picker/PickerTests.Windows.cs | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/Controls/tests/DeviceTests/Elements/Picker/PickerTests.Windows.cs b/src/Controls/tests/DeviceTests/Elements/Picker/PickerTests.Windows.cs index 08f118082b28..73f839cf8e57 100644 --- a/src/Controls/tests/DeviceTests/Elements/Picker/PickerTests.Windows.cs +++ b/src/Controls/tests/DeviceTests/Elements/Picker/PickerTests.Windows.cs @@ -56,6 +56,27 @@ public async Task VerticalOptionsInitializesCorrectly() await InvokeOnMainThreadAsync(() => Assert.Equal(UI.Xaml.VerticalAlignment.Bottom, GetPlatformVerticalOptions(handler.PlatformView))); } + [Fact(DisplayName = "Title maps to PlaceholderText")] + public async Task TitleMapsToPlaceholderText() + { + var picker = new Picker() + { + Title = "Select Option", + ItemsSource = new ObservableCollection() + { + "Item 1", + "Item 2" + } + }; + + var handler = await CreateHandlerAsync(picker); + + await InvokeOnMainThreadAsync(() => + { + Assert.Equal("Select Option", handler.PlatformView.PlaceholderText); + }); + } + protected Task GetPlatformControlText(ComboBox platformView) { return InvokeOnMainThreadAsync(() => From 2ae9b2a171207b3833fb69727873785da9a27c81 Mon Sep 17 00:00:00 2001 From: Mohammad Hossein Rastegarinia Date: Mon, 20 Apr 2026 17:05:02 +0000 Subject: [PATCH 03/10] remove dead ComboBox styles --- .../Platform/Windows/Styles/MauiComboBoxStyle.xaml | 13 ------------- src/Core/src/Platform/Windows/Styles/Resources.xaml | 1 - 2 files changed, 14 deletions(-) delete mode 100644 src/Core/src/Platform/Windows/Styles/MauiComboBoxStyle.xaml diff --git a/src/Core/src/Platform/Windows/Styles/MauiComboBoxStyle.xaml b/src/Core/src/Platform/Windows/Styles/MauiComboBoxStyle.xaml deleted file mode 100644 index f52b6279a916..000000000000 --- a/src/Core/src/Platform/Windows/Styles/MauiComboBoxStyle.xaml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/src/Core/src/Platform/Windows/Styles/Resources.xaml b/src/Core/src/Platform/Windows/Styles/Resources.xaml index 037beebde72e..3d47e34c94d0 100644 --- a/src/Core/src/Platform/Windows/Styles/Resources.xaml +++ b/src/Core/src/Platform/Windows/Styles/Resources.xaml @@ -5,7 +5,6 @@ x:Class="Microsoft.Maui.Platform.Resources"> - From 06c890ca649aa5ad947cd4149bcab587a43d126e Mon Sep 17 00:00:00 2001 From: Mohammad Hossein Rastegarinia Date: Mon, 20 Apr 2026 17:06:37 +0000 Subject: [PATCH 04/10] add UpdateTitleColor to PickerExtensions --- src/Core/src/Handlers/Picker/PickerHandler.Windows.cs | 2 +- src/Core/src/Platform/Windows/PickerExtensions.cs | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/Core/src/Handlers/Picker/PickerHandler.Windows.cs b/src/Core/src/Handlers/Picker/PickerHandler.Windows.cs index 7275ebf2c20a..224d16469b88 100644 --- a/src/Core/src/Handlers/Picker/PickerHandler.Windows.cs +++ b/src/Core/src/Handlers/Picker/PickerHandler.Windows.cs @@ -69,7 +69,7 @@ public static void MapTitle(IPickerHandler handler, IPicker picker) public static void MapTitleColor(IPickerHandler handler, IPicker picker) { - handler.PlatformView?.UpdateTitle(picker); + handler.PlatformView?.UpdateTitleColor(picker); } public static void MapBackground(IPickerHandler handler, IPicker picker) diff --git a/src/Core/src/Platform/Windows/PickerExtensions.cs b/src/Core/src/Platform/Windows/PickerExtensions.cs index 95468e0c3e1c..6a9d03df3372 100644 --- a/src/Core/src/Platform/Windows/PickerExtensions.cs +++ b/src/Core/src/Platform/Windows/PickerExtensions.cs @@ -12,6 +12,14 @@ public static void UpdateTitle(this ComboBox nativeComboBox, IPicker picker) nativeComboBox.PlaceholderText = picker.Title ?? string.Empty; } + public static void UpdateTitleColor(this ComboBox nativeComboBox, IPicker picker) + { + if (picker.TitleColor is null) + nativeComboBox.ClearValue(ComboBox.PlaceholderForegroundProperty); + else + nativeComboBox.PlaceholderForeground = picker.TitleColor.ToPlatform(); + } + public static void UpdateBackground(this ComboBox nativeComboBox, IPicker picker) { var platformBrush = picker.Background?.ToPlatform(); From c733de059b79105eb6df7c7767a80a80f5b198cd Mon Sep 17 00:00:00 2001 From: Mohammad Hossein Rastegarinia Date: Mon, 20 Apr 2026 17:06:53 +0000 Subject: [PATCH 05/10] add more tests --- .../Elements/Picker/PickerTests.Windows.cs | 65 +++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/src/Controls/tests/DeviceTests/Elements/Picker/PickerTests.Windows.cs b/src/Controls/tests/DeviceTests/Elements/Picker/PickerTests.Windows.cs index 73f839cf8e57..9e5916f11e28 100644 --- a/src/Controls/tests/DeviceTests/Elements/Picker/PickerTests.Windows.cs +++ b/src/Controls/tests/DeviceTests/Elements/Picker/PickerTests.Windows.cs @@ -8,6 +8,7 @@ using Microsoft.Maui.Platform; using Microsoft.UI.Xaml.Controls; using Xunit; +using WSolidColorBrush = Microsoft.UI.Xaml.Media.SolidColorBrush; namespace Microsoft.Maui.DeviceTests { @@ -77,6 +78,70 @@ await InvokeOnMainThreadAsync(() => }); } + [Fact(DisplayName = "Null title maps to empty PlaceholderText")] + public async Task NullTitleMapsToEmptyPlaceholderText() + { + var picker = new Picker() + { + Title = null, + ItemsSource = new ObservableCollection() + { + "Item 1", + "Item 2" + } + }; + + var handler = await CreateHandlerAsync(picker); + + await InvokeOnMainThreadAsync(() => + { + Assert.Equal(string.Empty, handler.PlatformView.PlaceholderText); + }); + } + + [Fact(DisplayName = "Empty title maps to empty PlaceholderText")] + public async Task EmptyTitleMapsToEmptyPlaceholderText() + { + var picker = new Picker() + { + Title = string.Empty, + ItemsSource = new ObservableCollection() + { + "Item 1", + "Item 2" + } + }; + + var handler = await CreateHandlerAsync(picker); + + await InvokeOnMainThreadAsync(() => + { + Assert.Equal(string.Empty, handler.PlatformView.PlaceholderText); + }); + } + + [Fact(DisplayName = "TitleColor maps to PlaceholderForeground")] + public async Task TitleColorMapsToPlaceholderForeground() + { + var picker = new Picker() + { + Title = "Select Option", + TitleColor = Colors.Red, + ItemsSource = new ObservableCollection() + { + "Item 1", + "Item 2" + } + }; + + var handler = await CreateHandlerAsync(picker); + + await InvokeOnMainThreadAsync(() => + { + var placeholderBrush = Assert.IsType(handler.PlatformView.PlaceholderForeground); + Assert.Equal(Colors.Red, placeholderBrush.Color.ToColor()); + }); + } protected Task GetPlatformControlText(ComboBox platformView) { return InvokeOnMainThreadAsync(() => From 93c2a47832ddfc2668e93d8efe8146c4a63bc65d Mon Sep 17 00:00:00 2001 From: Mohammad Hossein Rastegarinia Date: Wed, 29 Apr 2026 06:33:18 +0000 Subject: [PATCH 06/10] update unshipped public API text --- src/Core/src/PublicAPI/net-windows/PublicAPI.Unshipped.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Core/src/PublicAPI/net-windows/PublicAPI.Unshipped.txt b/src/Core/src/PublicAPI/net-windows/PublicAPI.Unshipped.txt index 7dc5c58110bf..efc3377d2189 100644 --- a/src/Core/src/PublicAPI/net-windows/PublicAPI.Unshipped.txt +++ b/src/Core/src/PublicAPI/net-windows/PublicAPI.Unshipped.txt @@ -1 +1,2 @@ #nullable enable +static Microsoft.Maui.Platform.PickerExtensions.UpdateTitleColor(this Microsoft.UI.Xaml.Controls.ComboBox! nativeComboBox, Microsoft.Maui.IPicker! picker) -> void From 61cf4b92e21275a403ea3b5c68e569218dc25ba4 Mon Sep 17 00:00:00 2001 From: Mohammad Hossein Rastegarinia Date: Sun, 3 May 2026 19:41:05 +0000 Subject: [PATCH 07/10] add more tests for TitleColor --- .../Elements/Picker/PickerTests.Windows.cs | 55 +++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/src/Controls/tests/DeviceTests/Elements/Picker/PickerTests.Windows.cs b/src/Controls/tests/DeviceTests/Elements/Picker/PickerTests.Windows.cs index 9e5916f11e28..e1592d2173d1 100644 --- a/src/Controls/tests/DeviceTests/Elements/Picker/PickerTests.Windows.cs +++ b/src/Controls/tests/DeviceTests/Elements/Picker/PickerTests.Windows.cs @@ -6,6 +6,7 @@ using Microsoft.Maui.Graphics; using Microsoft.Maui.Handlers; using Microsoft.Maui.Platform; +using Microsoft.UI.Xaml; using Microsoft.UI.Xaml.Controls; using Xunit; using WSolidColorBrush = Microsoft.UI.Xaml.Media.SolidColorBrush; @@ -142,6 +143,60 @@ await InvokeOnMainThreadAsync(() => Assert.Equal(Colors.Red, placeholderBrush.Color.ToColor()); }); } + + [Fact(DisplayName = "Null TitleColor clears local PlaceholderForeground")] + public async Task NullTitleColorClearsPlaceholderForegroundLocalValue() + { + var picker = new Picker() + { + Title = "Select Option", + TitleColor = Colors.Red, + ItemsSource = new ObservableCollection() + { + "Item 1", + "Item 2" + } + }; + + var handler = await CreateHandlerAsync(picker); + + await InvokeOnMainThreadAsync(() => + { + Assert.IsType(handler.PlatformView.PlaceholderForeground); + + picker.ClearValue(Picker.TitleColorProperty); + + Assert.Equal(DependencyProperty.UnsetValue, handler.PlatformView.ReadLocalValue(ComboBox.PlaceholderForegroundProperty)); + }); + } + + [Fact(DisplayName = "Title and TitleColor update after handler creation")] + public async Task TitleAndTitleColorUpdateAfterHandlerCreation() + { + var picker = new Picker() + { + Title = "First", + TitleColor = Colors.Red, + ItemsSource = new ObservableCollection() + { + "Item 1", + "Item 2" + } + }; + + var handler = await CreateHandlerAsync(picker); + + await InvokeOnMainThreadAsync(() => + { + picker.Title = "Second"; + Assert.Equal("Second", handler.PlatformView.PlaceholderText); + + picker.TitleColor = Colors.Blue; + var brush = Assert.IsType(handler.PlatformView.PlaceholderForeground); + Assert.Equal(Colors.Blue, brush.Color.ToColor()); + }); + } + protected Task GetPlatformControlText(ComboBox platformView) { return InvokeOnMainThreadAsync(() => From c3ff067196094dd1083e0cb03159a003e3014b8d Mon Sep 17 00:00:00 2001 From: Mohammad Hossein Rastegarinia Date: Sun, 3 May 2026 20:27:16 +0000 Subject: [PATCH 08/10] add CharacterSpacing test --- .../Elements/Picker/PickerTests.Windows.cs | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/src/Controls/tests/DeviceTests/Elements/Picker/PickerTests.Windows.cs b/src/Controls/tests/DeviceTests/Elements/Picker/PickerTests.Windows.cs index e1592d2173d1..970f47d7d508 100644 --- a/src/Controls/tests/DeviceTests/Elements/Picker/PickerTests.Windows.cs +++ b/src/Controls/tests/DeviceTests/Elements/Picker/PickerTests.Windows.cs @@ -197,6 +197,40 @@ await InvokeOnMainThreadAsync(() => }); } + [Fact(DisplayName = "CharacterSpacing propagates to placeholder TextBlock when Title is set")] + public async Task CharacterSpacingPropagatesToPlaceholderWithTitle() + { + const string title = "Select Option"; + const double characterSpacingPt = 8d; + var expectedEm = characterSpacingPt.ToEm(); + + var picker = new Picker() + { + Title = title, + CharacterSpacing = characterSpacingPt, + ItemsSource = new ObservableCollection() + { + "Item 1", + "Item 2" + }, + WidthRequest = 200, + HeightRequest = 48 + }; + + await CreateHandlerAndAddToWindow(picker, handler => + { + var platformView = handler.PlatformView; + + Assert.Equal(title, platformView.PlaceholderText); + Assert.Equal(expectedEm, platformView.CharacterSpacing); + + var placeholderTextBlock = platformView.GetDescendantByName("PlaceholderTextBlock"); + Assert.NotNull(placeholderTextBlock); + Assert.Equal(title, placeholderTextBlock.Text); + Assert.Equal(expectedEm, placeholderTextBlock.CharacterSpacing); + }); + } + protected Task GetPlatformControlText(ComboBox platformView) { return InvokeOnMainThreadAsync(() => From 179a333ac9c7762d4d3095e20dd30b699868f632 Mon Sep 17 00:00:00 2001 From: Mohammad Hossein Rastegarinia Date: Sat, 16 May 2026 06:37:13 +0000 Subject: [PATCH 09/10] resolve MauiBot review comments --- .../Elements/Picker/PickerTests.Windows.cs | 4 +-- .../src/Platform/Windows/PickerExtensions.cs | 26 ++++++++++++++++++- 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/src/Controls/tests/DeviceTests/Elements/Picker/PickerTests.Windows.cs b/src/Controls/tests/DeviceTests/Elements/Picker/PickerTests.Windows.cs index 970f47d7d508..b85a3120b05f 100644 --- a/src/Controls/tests/DeviceTests/Elements/Picker/PickerTests.Windows.cs +++ b/src/Controls/tests/DeviceTests/Elements/Picker/PickerTests.Windows.cs @@ -197,8 +197,8 @@ await InvokeOnMainThreadAsync(() => }); } - [Fact(DisplayName = "CharacterSpacing propagates to placeholder TextBlock when Title is set")] - public async Task CharacterSpacingPropagatesToPlaceholderWithTitle() + [Fact(DisplayName = "CharacterSpacing applies to placeholder TextBlock when Title is set")] + public async Task CharacterSpacingAppliesToPlaceholderWithTitle() { const string title = "Select Option"; const double characterSpacingPt = 8d; diff --git a/src/Core/src/Platform/Windows/PickerExtensions.cs b/src/Core/src/Platform/Windows/PickerExtensions.cs index 6a9d03df3372..24e803b80798 100644 --- a/src/Core/src/Platform/Windows/PickerExtensions.cs +++ b/src/Core/src/Platform/Windows/PickerExtensions.cs @@ -10,6 +10,7 @@ public static class PickerExtensions public static void UpdateTitle(this ComboBox nativeComboBox, IPicker picker) { nativeComboBox.PlaceholderText = picker.Title ?? string.Empty; + nativeComboBox.UpdatePlaceholderCharacterSpacing(); } public static void UpdateTitleColor(this ComboBox nativeComboBox, IPicker picker) @@ -79,6 +80,29 @@ public static void UpdateSelectedIndex(this ComboBox nativeComboBox, IPicker pic public static void UpdateCharacterSpacing(this ComboBox nativeComboBox, IPicker picker) { nativeComboBox.CharacterSpacing = picker.CharacterSpacing.ToEm(); + nativeComboBox.UpdatePlaceholderCharacterSpacing(); + } + + static void UpdatePlaceholderCharacterSpacing(this ComboBox nativeComboBox) + { + if (nativeComboBox.IsLoaded) + { + ApplyPlaceholderCharacterSpacing(nativeComboBox); + } + else + { + nativeComboBox.OnLoaded(() => ApplyPlaceholderCharacterSpacing(nativeComboBox)); + } + } + + static void ApplyPlaceholderCharacterSpacing(ComboBox nativeComboBox) + { + var placeholderTextBlock = nativeComboBox.GetDescendantByName("PlaceholderTextBlock"); + + if (placeholderTextBlock is not null) + { + placeholderTextBlock.CharacterSpacing = nativeComboBox.CharacterSpacing; + } } public static void UpdateFont(this ComboBox nativeComboBox, IPicker picker, IFontManager fontManager) => @@ -111,4 +135,4 @@ internal static void UpdateIsOpen(this ComboBox nativeComboBox, IPicker picker) nativeComboBox.IsDropDownOpen = picker.IsOpen; } } -} \ No newline at end of file +} From 142d93a2becdaa8f51ccb1c743b625fccbd7dae1 Mon Sep 17 00:00:00 2001 From: Mohammad Hossein Rastegarinia Date: Mon, 1 Jun 2026 08:16:52 +0000 Subject: [PATCH 10/10] fix CharacterSpacing test --- .../tests/DeviceTests/Elements/Picker/PickerTests.Windows.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Controls/tests/DeviceTests/Elements/Picker/PickerTests.Windows.cs b/src/Controls/tests/DeviceTests/Elements/Picker/PickerTests.Windows.cs index b85a3120b05f..757450e9fed9 100644 --- a/src/Controls/tests/DeviceTests/Elements/Picker/PickerTests.Windows.cs +++ b/src/Controls/tests/DeviceTests/Elements/Picker/PickerTests.Windows.cs @@ -217,7 +217,7 @@ public async Task CharacterSpacingAppliesToPlaceholderWithTitle() HeightRequest = 48 }; - await CreateHandlerAndAddToWindow(picker, handler => + await AttachAndRun(picker, handler => { var platformView = handler.PlatformView;