diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Issue30066.cs b/src/Controls/tests/TestCases.HostApp/Issues/Issue30066.cs new file mode 100644 index 000000000000..985d98daf5d8 --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/Issue30066.cs @@ -0,0 +1,63 @@ +using Microsoft.Maui.Controls; +using System; + +namespace Maui.Controls.Sample.Issues; + +[Issue(IssueTracker.Github, "30066", "DatePicker CharacterSpacing Property Not Working on Windows", PlatformAffected.UWP)] +public class Issue30066 : TestShell +{ + protected override void Init() + { + var shellContent = new ShellContent + { + Title = "DatePicker CharacterSpacing Test", + Content = new Issue30066ContentPage() { Title = "DatePicker CharacterSpacing Test" } + }; + + Items.Add(shellContent); + } + + class Issue30066ContentPage : ContentPage + { + public Issue30066ContentPage() + { + var datePicker = new DatePicker + { + Date = DateTime.Today, + CharacterSpacing = 10, + AutomationId = "TestDatePicker", + HorizontalOptions = LayoutOptions.Center, + VerticalOptions = LayoutOptions.Center, + }; + + var label = new Label + { + Text = "The DatePicker above should have character spacing of 10 applied to its text.", + HorizontalOptions = LayoutOptions.Center, + Margin = new Thickness(20), + HorizontalTextAlignment = TextAlignment.Center + }; + + var button = new Button + { + Text = "Change Character Spacing to 20", + AutomationId = "ChangeSpacingButton", + HorizontalOptions = LayoutOptions.Center, + Margin = new Thickness(0, 20) + }; + + button.Clicked += (s, e) => + { + datePicker.CharacterSpacing = datePicker.CharacterSpacing == 10 ? 20 : 10; + button.Text = $"Change Character Spacing to {(datePicker.CharacterSpacing == 10 ? 20 : 10)}"; + }; + + Content = new StackLayout + { + Children = { datePicker, label, button }, + Spacing = 20, + Margin = new Thickness(20) + }; + } + } +} \ No newline at end of file diff --git a/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue30066.cs b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue30066.cs new file mode 100644 index 000000000000..5ffcf5da66e8 --- /dev/null +++ b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue30066.cs @@ -0,0 +1,40 @@ +using NUnit.Framework; +using UITest.Appium; +using UITest.Core; + +namespace Microsoft.Maui.TestCases.Tests.Issues; + +public class Issue30066 : _IssuesUITest +{ + public Issue30066(TestDevice device) + : base(device) + { + } + + public override string Issue => "DatePicker CharacterSpacing Property Not Working on Windows"; + + [Test] + [Category(UITestCategories.DatePicker)] + public void DatePickerCharacterSpacingShouldApply() + { + App.WaitForElement("TestDatePicker"); + + // Take a screenshot to verify character spacing is applied + // On Windows, the DatePicker text should show increased character spacing + VerifyScreenshot(); + } + + [Test] + [Category(UITestCategories.DatePicker)] + public void DatePickerCharacterSpacingCanChange() + { + App.WaitForElement("TestDatePicker"); + App.WaitForElement("ChangeSpacingButton"); + + // Change the character spacing by clicking the button + App.Tap("ChangeSpacingButton"); + + // Take a screenshot to verify the character spacing changed + VerifyScreenshot(); + } +} \ No newline at end of file diff --git a/src/Core/src/Platform/Windows/CharacterSpacingExtensions.cs b/src/Core/src/Platform/Windows/CharacterSpacingExtensions.cs index 9577f4356321..5e65a3f2d9c6 100644 --- a/src/Core/src/Platform/Windows/CharacterSpacingExtensions.cs +++ b/src/Core/src/Platform/Windows/CharacterSpacingExtensions.cs @@ -8,5 +8,21 @@ public static int ToEm(this double pt) { return Convert.ToInt32(pt * 0.0624f * 1000); // Coefficient for converting Pt to Em. The value is uniform spacing between characters, in units of 1/1000 of an em. } + + /// + /// Converts character spacing from Em units back to the original double value. + /// + /// The character spacing value in Em units (1/1000 of an em) + /// The original character spacing value in points + /// + /// This method performs the inverse operation of ToEm(). + /// Em units are defined as 1/1000 of an em, where the conversion coefficient is 0.0624. + /// The calculation reverses: originalValue * 0.0624 * 1000 = emValue + /// So: originalValue = emValue / (0.0624 * 1000) + /// + public static double FromEm(this int emValue) + { + return emValue / (0.0624 * 1000); + } } } \ No newline at end of file diff --git a/src/Core/src/Platform/Windows/DatePickerExtensions.cs b/src/Core/src/Platform/Windows/DatePickerExtensions.cs index 70a06cf55e15..1179bf562526 100644 --- a/src/Core/src/Platform/Windows/DatePickerExtensions.cs +++ b/src/Core/src/Platform/Windows/DatePickerExtensions.cs @@ -1,4 +1,5 @@ using System; +using System.Linq; using Microsoft.Maui.Graphics; using Microsoft.UI.Xaml.Controls; using WBrush = Microsoft.UI.Xaml.Media.Brush; @@ -38,7 +39,34 @@ public static void UpdateMaximumDate(this CalendarDatePicker platformDatePicker, public static void UpdateCharacterSpacing(this CalendarDatePicker platformDatePicker, IDatePicker datePicker) { - platformDatePicker.CharacterSpacing = datePicker.CharacterSpacing.ToEm(); + // Store the character spacing value to apply it when ready + var characterSpacing = datePicker.CharacterSpacing; + + // Apply immediately if loaded, otherwise wait for load + if (platformDatePicker.IsLoaded) + { + ApplyCharacterSpacingToTextBlocks(platformDatePicker, characterSpacing); + } + else + { + // Wait for the control to load, then apply character spacing + platformDatePicker.OnLoaded(() => ApplyCharacterSpacingToTextBlocks(platformDatePicker, characterSpacing)); + } + } + + static void ApplyCharacterSpacingToTextBlocks(CalendarDatePicker platformDatePicker, double characterSpacing) + { + // Find all TextBlock elements within the CalendarDatePicker and apply character spacing + var textBlocks = platformDatePicker.GetChildren(); + var characterSpacingEm = characterSpacing.ToEm(); + + foreach (var textBlock in textBlocks) + { + if (textBlock is not null) + { + textBlock.CharacterSpacing = characterSpacingEm; + } + } } public static void UpdateFont(this CalendarDatePicker platformDatePicker, IDatePicker datePicker, IFontManager fontManager) => diff --git a/src/Core/src/PublicAPI/net-windows/PublicAPI.Unshipped.txt b/src/Core/src/PublicAPI/net-windows/PublicAPI.Unshipped.txt index 7dc5c58110bf..ff62289f322e 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.CharacterSpacingExtensions.FromEm(this int emValue) -> double diff --git a/src/Core/tests/DeviceTests/Handlers/DatePicker/DatePickerHandlerTests.Windows.cs b/src/Core/tests/DeviceTests/Handlers/DatePicker/DatePickerHandlerTests.Windows.cs index c077a59de555..9cbfc2910122 100644 --- a/src/Core/tests/DeviceTests/Handlers/DatePicker/DatePickerHandlerTests.Windows.cs +++ b/src/Core/tests/DeviceTests/Handlers/DatePicker/DatePickerHandlerTests.Windows.cs @@ -2,6 +2,7 @@ using System.Threading.Tasks; using Microsoft.Maui.Controls; using Microsoft.Maui.DeviceTests.Stubs; +using Microsoft.Maui.Platform; using Microsoft.UI.Xaml.Controls; using Xunit; @@ -89,5 +90,53 @@ Color GetNativeTextColor(DatePickerHandler datePickerHandler) return null; } + + [Fact] + public async Task CharacterSpacingInitializesCorrectly() + { + var datePicker = new DatePickerStub() + { + Date = DateTime.Today, + CharacterSpacing = 10 + }; + + await ValidatePropertyInitValue(datePicker, () => datePicker.CharacterSpacing, GetNativeCharacterSpacing, 10.0); + } + + double GetNativeCharacterSpacing(DatePickerHandler datePickerHandler) + { + var platformDatePicker = GetNativeDatePicker(datePickerHandler); + + // Since CalendarDatePicker doesn't have CharacterSpacing property directly, + // we need to check if it was applied to internal TextBlock elements + var textBlocks = platformDatePicker.GetChildren(); + foreach (var textBlock in textBlocks) + { + if (textBlock is not null && textBlock.CharacterSpacing > 0) + { + // Convert back from Em to original value using the extension method + return textBlock.CharacterSpacing.FromEm(); + } + } + + return 0.0; + } + + [Fact] + public async Task CharacterSpacingUpdatesCorrectly() + { + var datePicker = new DatePickerStub() + { + Date = DateTime.Today, + CharacterSpacing = 5 + }; + + await ValidatePropertyUpdatesValue( + datePicker, + nameof(IDatePicker.CharacterSpacing), + GetNativeCharacterSpacing, + 5.0, + 15.0); + } } }