فهرست منبع

Fix TimePicker empty designator on 12 hour clock (#13469)

* Test - On empty PM/AM designator on culture info the time picker should show AM/PM

* On empty PM/AM designator on culture info the time picker should show AM/PM
Marko Prosen 1 سال پیش
والد
کامیت
f6c5720e7a

+ 2 - 2
src/Avalonia.Controls/DateTimePickers/DateTimePickerPanel.cs

@@ -2,6 +2,7 @@
 using System.Globalization;
 using System.Linq;
 using Avalonia.Controls.Presenters;
+using Avalonia.Controls.Utils;
 using Avalonia.Input;
 using Avalonia.Input.GestureRecognizers;
 using Avalonia.Interactivity;
@@ -516,8 +517,7 @@ namespace Avalonia.Controls.Primitives
                 case DateTimePickerPanelType.Minute:
                     return new TimeSpan(0, value, 0).ToString(ItemFormat);
                 case DateTimePickerPanelType.TimePeriod:
-                    return value == MinimumValue ? CultureInfo.CurrentCulture.DateTimeFormat.AMDesignator :
-                        CultureInfo.CurrentCulture.DateTimeFormat.PMDesignator;
+                    return value == MinimumValue ? TimeUtils.GetAMDesignator() : TimeUtils.GetPMDesignator();
                 default:
                         return "";
             }

+ 3 - 4
src/Avalonia.Controls/DateTimePickers/TimePicker.cs

@@ -5,6 +5,7 @@ using Avalonia.Data;
 using Avalonia.Layout;
 using System;
 using System.Globalization;
+using Avalonia.Controls.Utils;
 
 namespace Avalonia.Controls
 {
@@ -227,8 +228,7 @@ namespace Avalonia.Controls
                 _minuteText.Text = newTime.ToString("mm");
                 PseudoClasses.Set(":hasnotime", false);
 
-                _periodText.Text = time.Value.Hours >= 12 ? CultureInfo.CurrentCulture.DateTimeFormat.PMDesignator :
-                    CultureInfo.CurrentCulture.DateTimeFormat.AMDesignator;
+                _periodText.Text = time.Value.Hours >= 12 ? TimeUtils.GetPMDesignator() : TimeUtils.GetAMDesignator();
             }
             else
             {
@@ -236,8 +236,7 @@ namespace Avalonia.Controls
                 _minuteText.Text = "minute";
                 PseudoClasses.Set(":hasnotime", true);
 
-                _periodText.Text = DateTime.Now.Hour >= 12 ? CultureInfo.CurrentCulture.DateTimeFormat.PMDesignator :
-                    CultureInfo.CurrentCulture.DateTimeFormat.AMDesignator;
+                _periodText.Text = DateTime.Now.Hour >= 12 ?  TimeUtils.GetPMDesignator() :  TimeUtils.GetAMDesignator();
             }
         }
 

+ 16 - 0
src/Avalonia.Controls/Utils/TimeUtils.cs

@@ -0,0 +1,16 @@
+using System.Globalization;
+
+namespace Avalonia.Controls.Utils;
+
+internal static class TimeUtils
+{
+    public static string GetPMDesignator() =>
+        !string.IsNullOrEmpty(CultureInfo.CurrentCulture.DateTimeFormat.PMDesignator) ?
+            CultureInfo.CurrentCulture.DateTimeFormat.PMDesignator :
+            CultureInfo.InvariantCulture.DateTimeFormat.PMDesignator;
+
+    public static string GetAMDesignator() =>
+        !string.IsNullOrEmpty(CultureInfo.CurrentCulture.DateTimeFormat.AMDesignator) ?
+            CultureInfo.CurrentCulture.DateTimeFormat.AMDesignator :
+            CultureInfo.InvariantCulture.DateTimeFormat.AMDesignator;
+}

+ 34 - 0
tests/Avalonia.Controls.UnitTests/TimePickerTests.cs

@@ -98,6 +98,40 @@ namespace Avalonia.Controls.UnitTests
                 Assert.True(minuteText.Text == "minute");
             }
         }
+        
+        [Fact]
+        [UseEmptyDesignatorCulture]
+        public void Using_12HourClock_On_Culture_With_Empty_Period_Should_Show_Period()
+        {
+            using (UnitTestApplication.Start(Services))
+            {
+                TimePicker timePicker = new TimePicker()
+                {
+                    Template = CreateTemplate(), ClockIdentifier = "12HourClock",
+                };
+                timePicker.ApplyTemplate();
+
+                var desc = timePicker.GetVisualDescendants();
+                Assert.True(desc.Count() > 1); //Should be layoutroot grid & button
+
+                Assert.True(desc.ElementAt(1) is Button);
+
+                var container = (desc.ElementAt(1) as Button).Content as Grid;
+                Assert.True(container != null);
+
+                var periodTextHost = container.Children[4] as Border;
+                Assert.NotNull(periodTextHost);
+                var periodText = periodTextHost.Child as TextBlock;
+                Assert.NotNull(periodTextHost);
+
+                TimeSpan ts = TimeSpan.FromHours(10);
+                timePicker.SelectedTime = ts;
+                Assert.False(string.IsNullOrEmpty(periodText.Text));
+
+                timePicker.SelectedTime = null;
+                Assert.False(string.IsNullOrEmpty(periodText.Text));
+            }
+        }
 
         private static TestServices Services => TestServices.MockThreadingInterface.With(
             fontManagerImpl: new HeadlessFontManagerStub(),

+ 37 - 0
tests/Avalonia.UnitTests/UseEmptyDesignatorCultureAttribute.cs

@@ -0,0 +1,37 @@
+#nullable enable
+
+using System;
+using System.Globalization;
+using System.Reflection;
+using Xunit.Sdk;
+
+namespace Avalonia.UnitTests;
+
+[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
+public sealed class UseEmptyDesignatorCultureAttribute : BeforeAfterTestAttribute
+{
+    private CultureInfo? _previousCulture;
+    private CultureInfo? _previousUICulture;
+
+    private CultureInfo CultureInfo { get; } =
+        new(string.Empty, false) { DateTimeFormat = { AMDesignator = string.Empty, PMDesignator = string.Empty } };
+
+    public override void Before(MethodInfo methodUnderTest)
+    {
+        base.Before(methodUnderTest);
+
+        _previousCulture = CultureInfo.CurrentCulture;
+        _previousUICulture = CultureInfo.CurrentUICulture;
+
+        CultureInfo.CurrentCulture = CultureInfo;
+        CultureInfo.CurrentUICulture = CultureInfo;
+    }
+
+    public override void After(MethodInfo methodUnderTest)
+    {
+        CultureInfo.CurrentCulture = _previousCulture!;
+        CultureInfo.CurrentUICulture = _previousUICulture!;
+
+        base.After(methodUnderTest);
+    }
+}