diff --git a/src/BootstrapBlazor.Shared/Demos/DateTimePicker/DateTimePickerPlacement.razor b/src/BootstrapBlazor.Shared/Demos/DateTimePicker/DateTimePickerBindValueDemo.razor similarity index 61% rename from src/BootstrapBlazor.Shared/Demos/DateTimePicker/DateTimePickerPlacement.razor rename to src/BootstrapBlazor.Shared/Demos/DateTimePicker/DateTimePickerBindValueDemo.razor index 2fb9ae5fb235b1747150ecc1797b82d92907b0f8..028c1a5cc613ae5fbf63fab523491570566fc3da 100644 --- a/src/BootstrapBlazor.Shared/Demos/DateTimePicker/DateTimePickerPlacement.razor +++ b/src/BootstrapBlazor.Shared/Demos/DateTimePicker/DateTimePickerBindValueDemo.razor @@ -1,6 +1,6 @@ 
- +
@@ -10,15 +10,9 @@ @code { private DateTime? BindValue { get; set; } = DateTime.Today; - private Task DateTimeValueChanged(DateTime? d) - { - BindValue = d; - return Task.CompletedTask; - } - private string BindValueString { get => BindValue.HasValue ? BindValue.Value.ToString("yyyy-MM-dd") : ""; - set => BindValue = DateTime.TryParse(value, out var d) ? d : DateTime.Today; + set => BindValue = DateTime.TryParse(value, out var d) ? d : null; } } diff --git a/src/BootstrapBlazor.Shared/Demos/DateTimePicker/DateTimePickerDate.razor b/src/BootstrapBlazor.Shared/Demos/DateTimePicker/DateTimePickerDate.razor deleted file mode 100644 index b17fd6bd5e889d142e7816062739707919d3688c..0000000000000000000000000000000000000000 --- a/src/BootstrapBlazor.Shared/Demos/DateTimePicker/DateTimePickerDate.razor +++ /dev/null @@ -1 +0,0 @@ - diff --git a/src/BootstrapBlazor.Shared/Demos/DateTimePicker/DateTimePickerDateTimeOffsetDemo.razor b/src/BootstrapBlazor.Shared/Demos/DateTimePicker/DateTimePickerDateTimeOffsetDemo.razor new file mode 100644 index 0000000000000000000000000000000000000000..b2a2350d50a7f38146141c563a7e40067c4d3bd1 --- /dev/null +++ b/src/BootstrapBlazor.Shared/Demos/DateTimePicker/DateTimePickerDateTimeOffsetDemo.razor @@ -0,0 +1,5 @@ + + +@code { + private DateTimeOffset? Value { get; set; } = DateTimeOffset.Now; +} diff --git a/src/BootstrapBlazor.Shared/Demos/DateTimePicker/DateTimePickerNullValue.razor b/src/BootstrapBlazor.Shared/Demos/DateTimePicker/DateTimePickerNullValue.razor index 5ab30455bd0bfd5d582b6e6c26b11b4e7520bfba..9df831039b7b32bbde20e51ca43bbc6285e6ab69 100644 --- a/src/BootstrapBlazor.Shared/Demos/DateTimePicker/DateTimePickerNullValue.razor +++ b/src/BootstrapBlazor.Shared/Demos/DateTimePicker/DateTimePickerNullValue.razor @@ -1,6 +1,6 @@ 
- +
diff --git a/src/BootstrapBlazor.Shared/Demos/DateTimePicker/DateTimePickerShowLabel.razor b/src/BootstrapBlazor.Shared/Demos/DateTimePicker/DateTimePickerShowLabel.razor index 73adba222a87074d185198375c8d7c5b0368895a..77331e1d9d96dc9c08a8ea01306092b6ae90a803 100644 --- a/src/BootstrapBlazor.Shared/Demos/DateTimePicker/DateTimePickerShowLabel.razor +++ b/src/BootstrapBlazor.Shared/Demos/DateTimePicker/DateTimePickerShowLabel.razor @@ -1,6 +1,6 @@ @inject IStringLocalizer Localizer - + @code { private DateTime? BindNullValue { get; set; } diff --git a/src/BootstrapBlazor.Shared/Demos/DateTimePicker/DateTimePickerValidateDemo.razor b/src/BootstrapBlazor.Shared/Demos/DateTimePicker/DateTimePickerValidateDemo.razor index 2ce3525636b27abe1894ab1e5cf6b8190566e0d6..e7e253460312122d214bdabb7fd5bc545020d0c2 100644 --- a/src/BootstrapBlazor.Shared/Demos/DateTimePicker/DateTimePickerValidateDemo.razor +++ b/src/BootstrapBlazor.Shared/Demos/DateTimePicker/DateTimePickerValidateDemo.razor @@ -6,28 +6,15 @@
-
@code { - /// - /// SubmitText - /// - private string? SubmitText { get; set; } - /// /// ModelValidateValue /// [Required] public DateTime? Value { get; set; } - - /// - /// OnInitialized 方法 - /// - protected override void OnInitialized() - { - SubmitText ??= Localizer[nameof(SubmitText)]; - } } diff --git a/src/BootstrapBlazor.Shared/Locales/en.json b/src/BootstrapBlazor.Shared/Locales/en.json index be8e09c1ffcd5bcbd011c789eea0ee715f33d6e7..74490a122adc5f48fc1ff6fc5844341ff7d7dc4d 100644 --- a/src/BootstrapBlazor.Shared/Locales/en.json +++ b/src/BootstrapBlazor.Shared/Locales/en.json @@ -2559,10 +2559,10 @@ "TimeIntro": "Click the confirm button to select the box value consistent with the text box value", "ValidateFormTitle": "Client validation", "ValidateFormIntro": "Check data validity and prompt automatically based on custom validation rules", - "DateTitle": "Click on the pop-up date box", - "DateIntro": "Select the control based on the date of the day in 「day」 as the base unit", - "PlacementTitle": "Data is bound in both directions", - "PlacementIntro": "The values in the text box change as the date component time changes", + "DateTimeOffsetTitle": "Click on the pop-up date box", + "DateTimeOffsetIntro": "Select the control based on the date of the day in 「day」 as the base unit", + "BindValueTitle": "Data is bound in both directions", + "BindValueIntro": "The values in the text box change as the date component time changes", "ViewModeTitle": "Selector with time", "ViewModeIntro": "Select the date and time in the same selector, click the confirm button and close the pop-up window", "ViewModeTip": "Set the value of the viewMode property to The DateTime of DatePickerViewMode.DateTime", diff --git a/src/BootstrapBlazor.Shared/Locales/zh.json b/src/BootstrapBlazor.Shared/Locales/zh.json index 05bd406845785cf4f3f44958f0f7773d793d9192..01e15baab7e0665dcdafa28100f49839ac42f211 100644 --- a/src/BootstrapBlazor.Shared/Locales/zh.json +++ b/src/BootstrapBlazor.Shared/Locales/zh.json @@ -2566,10 +2566,10 @@ "TimeIntro": "点击确认按钮时间选择框值与文本框值一致", "ValidateFormTitle": "客户端验证", "ValidateFormIntro": "根据自定义验证规则进行数据有效性检查并自动提示", - "DateTitle": "点击弹出日期框", - "DateIntro": "以「日」为基本单位,基础的日期选择控件", - "PlacementTitle": "数据双向绑定", - "PlacementIntro": "日期组件时间改变时文本框内的数值也跟着改变", + "DateTimeOffsetTitle": "点击弹出日期框", + "DateTimeOffsetIntro": "以「日」为基本单位,基础的日期选择控件,此示例绑定 DateTimeOffset 数据类型", + "BindValueTitle": "数据双向绑定", + "BindValueIntro": "日期组件时间改变时文本框内的数值也跟着改变", "ViewModeTitle": "带时间的选择器", "ViewModeIntro": "在同一个选择器里选择日期和时间,点击确认按钮后关闭弹窗", "ViewModeTip": "设置 ViewMode 属性值为 DatePickerViewMode.DateTime", diff --git a/src/BootstrapBlazor.Shared/Samples/DateTimePickers.razor b/src/BootstrapBlazor.Shared/Samples/DateTimePickers.razor index b9a2f15b589f98f7797893522edbee1bf7fa4243..d61475fd253606e9e0a39e009be8feeeda49e291 100644 --- a/src/BootstrapBlazor.Shared/Samples/DateTimePickers.razor +++ b/src/BootstrapBlazor.Shared/Samples/DateTimePickers.razor @@ -12,9 +12,9 @@ - + - +

@((MarkupString)Localizer["ViewModeTip"].Value)

diff --git a/src/BootstrapBlazor/BootstrapBlazor.csproj b/src/BootstrapBlazor/BootstrapBlazor.csproj index 8470706856182e71e25c3e5014fb0ae4beca948e..dfb5556c0d05dd9c04bbc7ba9e7056eba46fda48 100644 --- a/src/BootstrapBlazor/BootstrapBlazor.csproj +++ b/src/BootstrapBlazor/BootstrapBlazor.csproj @@ -1,7 +1,7 @@ - 7.1.9-beta04 + 7.2.0 diff --git a/src/BootstrapBlazor/Components/DateTimePicker/DatePickerBody.razor.cs b/src/BootstrapBlazor/Components/DateTimePicker/DatePickerBody.razor.cs index cecf5592f4be7cb6f6cf273096282f09fc2acd5f..9db39665db2d98fb086e899872a86c43cff921c8 100644 --- a/src/BootstrapBlazor/Components/DateTimePicker/DatePickerBody.razor.cs +++ b/src/BootstrapBlazor/Components/DateTimePicker/DatePickerBody.razor.cs @@ -57,9 +57,7 @@ public partial class DatePickerBody .AddClass("current", day == Value && Ranger == null && day.Month == CurrentDate.Month && !overflow) .AddClass("start", Ranger != null && day == Ranger.SelectedValue.Start.Date) .AddClass("end", Ranger != null && day == Ranger.SelectedValue.End.Date) - .AddClass("range", Ranger != null && CurrentDate.Month >= Ranger.SelectedValue.Start.Month - && Ranger.SelectedValue.Start != DateTime.MinValue && Ranger.SelectedValue.End != DateTime.MinValue - && day >= Ranger.SelectedValue.Start && day <= Ranger.SelectedValue.End) + .AddClass("range", Ranger != null && day >= Ranger.SelectedValue.Start && day <= Ranger.SelectedValue.End) .AddClass("today", day == DateTime.Today) .AddClass("disabled", IsDisabled(day) || overflow) .Build(); diff --git a/src/BootstrapBlazor/Components/DateTimePicker/DateTimePicker.razor.cs b/src/BootstrapBlazor/Components/DateTimePicker/DateTimePicker.razor.cs index d98700a85a04f072589c5047a2a9405b7a8c8b6a..d934f55555a1163e001c4030767b2d3062929414 100644 --- a/src/BootstrapBlazor/Components/DateTimePicker/DateTimePicker.razor.cs +++ b/src/BootstrapBlazor/Components/DateTimePicker/DateTimePicker.razor.cs @@ -137,6 +137,13 @@ public partial class DateTimePicker { base.OnParametersSet(); + DateTimePlaceHolderText ??= Localizer[nameof(DateTimePlaceHolderText)]; + DatePlaceHolderText ??= Localizer[nameof(DatePlaceHolderText)]; + GenericTypeErroMessage ??= Localizer[nameof(GenericTypeErroMessage)]; + DateTimeFormat ??= Localizer[nameof(DateTimeFormat)]; + DateFormat ??= Localizer[nameof(DateFormat)]; + Icon ??= "fa-regular fa-calendar-days"; + var type = typeof(TValue); // 判断泛型类型 @@ -145,13 +152,6 @@ public partial class DateTimePicker throw new InvalidOperationException(GenericTypeErroMessage); } - DateTimePlaceHolderText ??= Localizer[nameof(DateTimePlaceHolderText)]; - DatePlaceHolderText ??= Localizer[nameof(DatePlaceHolderText)]; - GenericTypeErroMessage ??= Localizer[nameof(GenericTypeErroMessage)]; - DateTimeFormat ??= Localizer[nameof(DateTimeFormat)]; - DateFormat ??= Localizer[nameof(DateFormat)]; - Icon ??= "fa-regular fa-calendar-days"; - // 泛型设置为可为空 AllowNull = Nullable.GetUnderlyingType(type) != null; @@ -167,13 +167,25 @@ public partial class DateTimePicker } // Value 为 MinValue 时 设置 Value 默认值 - if (AutoToday) + if (AutoToday && (Value == null || Value.ToString() == DateTime.MinValue.ToString())) { - if (Value == null || Value.ToString() == DateTime.MinValue.ToString()) + SelectedValue = DateTime.Today; + if (!AllowNull) { - SelectedValue = DateTime.Today; + CurrentValueAsString = SelectedValue.ToString("yyyy-MM-dd HH:mm:ss"); } } + else if (Value is DateTime dt) + { + SelectedValue = dt; + } + else + { + var offset = (DateTimeOffset?)(object)Value; + SelectedValue = offset.HasValue + ? offset.Value.DateTime + : DateTime.MinValue; + } } /// diff --git a/src/BootstrapBlazor/Components/DateTimeRange/DateTimeRange.razor.cs b/src/BootstrapBlazor/Components/DateTimeRange/DateTimeRange.razor.cs index 7d4efdeed31ae79471c390f667cfc0b169f5ef75..ab5b283f1177f2198d4aeeb6380cfe7dcceecabb 100644 --- a/src/BootstrapBlazor/Components/DateTimeRange/DateTimeRange.razor.cs +++ b/src/BootstrapBlazor/Components/DateTimeRange/DateTimeRange.razor.cs @@ -324,7 +324,7 @@ public partial class DateTimeRange /// internal void UpdateStart(DateTime d) { - StartValue = StartValue.AddYears(d.Year - StartValue.Year).AddMonths(d.Month - StartValue.Month); + StartValue = d; EndValue = StartValue.AddMonths(1); StateHasChanged(); } @@ -335,7 +335,7 @@ public partial class DateTimeRange /// internal void UpdateEnd(DateTime d) { - EndValue = EndValue.AddYears(d.Year - EndValue.Year).AddMonths(d.Month - EndValue.Month); + EndValue = d; StartValue = EndValue.AddMonths(-1); StateHasChanged(); } @@ -364,11 +364,12 @@ public partial class DateTimeRange SelectedValue.End = DateTime.MinValue; } - if (d.Year < StartValue.Year || d.Month < StartValue.Month) + var startDate = StartValue.AddDays(1 - StartValue.Day); + if (d < startDate) { UpdateStart(d); } - else if (d.Month > EndValue.Month) + else if (d > startDate.AddMonths(2).AddDays(-1)) { UpdateEnd(d); } diff --git a/test/UnitTest/Components/DateTimePickerTest.cs b/test/UnitTest/Components/DateTimePickerTest.cs index b9a8da51039fe5ff14c999b2badd1d78276cc1a4..ec9fa74bcabb8e6f97cea24d31b945df5581814c 100644 --- a/test/UnitTest/Components/DateTimePickerTest.cs +++ b/test/UnitTest/Components/DateTimePickerTest.cs @@ -17,7 +17,61 @@ public class DateTimePickerTest : BootstrapBlazorTestBase pb.Add(a => a.Value, DateTime.MinValue); }); // 设置 Value 为 MinValue 内部更改为 DateTime.Now - Assert.NotEqual(DateTime.MinValue, cut.Instance.Value); + Assert.Equal(DateTime.MinValue, cut.Instance.Value); + } + + [Fact] + public void AutoToday_Ok() + { + var cut = Context.RenderComponent>(pb => + { + pb.Add(a => a.Value, DateTime.MinValue); + }); + Assert.Equal(DateTime.Today, cut.Instance.Value); + + cut.SetParametersAndRender(pb => + { + pb.Add(a => a.AutoToday, false); + pb.Add(a => a.Value, DateTime.MinValue); + }); + Assert.Equal(DateTime.MinValue, cut.Instance.Value); + } + + [Fact] + public void AllowNull_Ok() + { + var cut = Context.RenderComponent>(pb => + { + pb.Add(a => a.Value, DateTime.MinValue); + }); + Assert.Equal(DateTime.MinValue, cut.Instance.Value); + } + + [Fact] + public void DataTimeOffsetNull_Ok() + { + var cut = Context.RenderComponent>(pb => + { + pb.Add(a => a.Value, DateTimeOffset.MinValue); + }); + Assert.Equal(DateTimeOffset.MinValue, cut.Instance.Value); + + cut.SetParametersAndRender(pb => + { + pb.Add(a => a.Value, null); + pb.Add(a => a.AutoToday, false); + }); + Assert.Null(cut.Instance.Value); + } + + [Fact] + public void DataTimeOffset_Ok() + { + var cut = Context.RenderComponent>(pb => + { + pb.Add(a => a.Value, DateTimeOffset.MinValue); + }); + Assert.Equal(DateTimeOffset.MinValue, cut.Instance.Value); } [Fact] @@ -105,6 +159,13 @@ public class DateTimePickerTest : BootstrapBlazorTestBase cut.InvokeAsync(() => buttons[0].Click()); Assert.Null(cut.Instance.Value); + + cut.SetParametersAndRender(pb => + { + pb.Add(a => a.AutoToday, false); + }); + cut.InvokeAsync(() => buttons[0].Click()); + Assert.Null(cut.Instance.Value); } [Fact] @@ -753,7 +814,6 @@ public class DateTimePickerTest : BootstrapBlazorTestBase Assert.True(confirm); } - [JSModuleNotInherited] class MockDateTimePicker : DatePickerBody { public static bool GetSafeYearDateTime_Ok() diff --git a/test/UnitTest/Components/DateTimeRangeTest.cs b/test/UnitTest/Components/DateTimeRangeTest.cs index d5afd323353686820fe6f667d83175b2d63dac9a..9f7ec272fcc66797da947b302b5e46d420e063a4 100644 --- a/test/UnitTest/Components/DateTimeRangeTest.cs +++ b/test/UnitTest/Components/DateTimeRangeTest.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Website: https://www.blazor.zone or https://argozhang.github.io/ +using AngleSharp.Dom; using System.ComponentModel.DataAnnotations; namespace UnitTest.Components; @@ -30,6 +31,26 @@ public class DateTimeRangeTest : BootstrapBlazorTestBase // 内部 StartValue 自动减一个月 } + [Fact] + public void RangeValue_Ok() + { + var cut = Context.RenderComponent(); + var cells = cut.FindAll(".date-table tbody span"); + var end = cells.First(i => i.TextContent == "7"); + var first = cells.First(i => i.TextContent == "1"); + cut.InvokeAsync(() => end.Click()); + cut.InvokeAsync(() => first.Click()); + + // confirm + var confirm = cut.FindAll(".is-confirm").Last(); + cut.InvokeAsync(() => confirm.Click()); + var value = cut.Instance.Value; + var startDate = DateTime.Today.AddDays(1 - DateTime.Today.Day); + var endDate = startDate.AddDays(7).AddSeconds(-1); + Assert.Equal(startDate, value.Start); + Assert.Equal(endDate, value.End); + } + [Fact] public void TodayButtonText_Ok() {