diff --git a/BlazorAppTest/BlazorAppTest.csproj b/BlazorAppTest/BlazorAppTest.csproj index 643433d37..b3c60ca51 100644 --- a/BlazorAppTest/BlazorAppTest.csproj +++ b/BlazorAppTest/BlazorAppTest.csproj @@ -1,7 +1,7 @@  - net8.0 + net8.0;net7.0;net6.0 enable diff --git a/Havit.Blazor.Components.Web.Bootstrap/Forms/HxCheckbox.cs b/Havit.Blazor.Components.Web.Bootstrap/Forms/HxCheckbox.cs index a38752f30..607e24615 100644 --- a/Havit.Blazor.Components.Web.Bootstrap/Forms/HxCheckbox.cs +++ b/Havit.Blazor.Components.Web.Bootstrap/Forms/HxCheckbox.cs @@ -86,6 +86,9 @@ protected override void BuildRenderInput(RenderTreeBuilder builder) BuildRenderInput_AddCommonAttributes(builder, "checkbox"); builder.AddAttribute(1000, "checked", BindConverter.FormatValue(CurrentValue)); builder.AddAttribute(1001, "onchange", value: EventCallback.Factory.CreateBinder(this, value => CurrentValue = value, CurrentValue)); +#if NET8_0_OR_GREATER + builder.SetUpdatesAttributeName("checked"); +#endif builder.AddEventStopPropagationAttribute(1002, "onclick", true); builder.AddElementReferenceCapture(1003, elementReference => InputElement = elementReference); builder.CloseElement(); // input diff --git a/Havit.Blazor.Components.Web.Bootstrap/Forms/HxInputNumber.cs b/Havit.Blazor.Components.Web.Bootstrap/Forms/HxInputNumber.cs index fa2af3220..7e13401b4 100644 --- a/Havit.Blazor.Components.Web.Bootstrap/Forms/HxInputNumber.cs +++ b/Havit.Blazor.Components.Web.Bootstrap/Forms/HxInputNumber.cs @@ -167,7 +167,9 @@ protected override void BuildRenderInput(RenderTreeBuilder builder) builder.AddAttribute(1002, "onfocus", "this.select();"); // source: https://stackoverflow.com/questions/4067469/selecting-all-text-in-html-text-input-when-clicked builder.AddAttribute(1003, "onchange", EventCallback.Factory.CreateBinder(this, value => CurrentValueAsString = value, CurrentValueAsString)); - +#if NET8_0_OR_GREATER + builder.SetUpdatesAttributeName("value"); +#endif // normalize pasted value builder.AddAttribute(1004, "onpaste", @"this.value = event.clipboardData.getData('text/plain').replace(/[^\d.,\-eE]/g, ''); this.dispatchEvent(new Event('change')); return false;"); diff --git a/Havit.Blazor.Components.Web.Bootstrap/Forms/HxInputRange.cs b/Havit.Blazor.Components.Web.Bootstrap/Forms/HxInputRange.cs index 70cbfa602..b50eb9154 100644 --- a/Havit.Blazor.Components.Web.Bootstrap/Forms/HxInputRange.cs +++ b/Havit.Blazor.Components.Web.Bootstrap/Forms/HxInputRange.cs @@ -87,7 +87,9 @@ protected override void BuildRenderInput(RenderTreeBuilder builder) builder.AddAttribute(4, "value", BindConverter.FormatValue(Value)); builder.AddAttribute(5, BindEventEffective.ToEventName(), EventCallback.Factory.CreateBinder(this, async value => await HandleValueChanged(value), Value)); - +#if NET8_0_OR_GREATER + builder.SetUpdatesAttributeName("value"); +#endif builder.AddAttribute(10, "min", Min); builder.AddAttribute(11, "max", Max); diff --git a/Havit.Blazor.Components.Web.Bootstrap/Forms/HxInputTextBase.cs b/Havit.Blazor.Components.Web.Bootstrap/Forms/HxInputTextBase.cs index 9ff52bdd6..f8c9bd4f0 100644 --- a/Havit.Blazor.Components.Web.Bootstrap/Forms/HxInputTextBase.cs +++ b/Havit.Blazor.Components.Web.Bootstrap/Forms/HxInputTextBase.cs @@ -76,8 +76,8 @@ protected override void BuildRenderInput(RenderTreeBuilder builder) builder.AddAttribute(1002, "value", FormatValueAsString(Value)); builder.AddAttribute(1003, BindEvent.ToEventName(), EventCallback.Factory.CreateBinder(this, value => CurrentValueAsString = value, CurrentValueAsString)); - #if NET8_0_OR_GREATER + builder.SetUpdatesAttributeName("value"); if (!String.IsNullOrEmpty(this.NameAttributeValue)) { builder.AddAttribute(1004, "name", NameAttributeValue); diff --git a/Havit.Blazor.Components.Web.Bootstrap/Forms/HxRadioButtonListBase.cs b/Havit.Blazor.Components.Web.Bootstrap/Forms/HxRadioButtonListBase.cs index a7a4a752c..58fd1ae09 100644 --- a/Havit.Blazor.Components.Web.Bootstrap/Forms/HxRadioButtonListBase.cs +++ b/Havit.Blazor.Components.Web.Bootstrap/Forms/HxRadioButtonListBase.cs @@ -157,6 +157,9 @@ protected void BuildRenderInput_RenderRadioItem(RenderTreeBuilder builder, int i builder.AddAttribute(207, "disabled", !CascadeEnabledComponent.EnabledEffective(this)); int j = index; builder.AddAttribute(208, "onclick", EventCallback.Factory.Create(this, () => HandleInputClick(j))); +#if NET8_0_OR_GREATER + builder.SetUpdatesAttributeName("checked"); +#endif builder.AddEventStopPropagationAttribute(209, "onclick", true); builder.AddMultipleAttributes(250, this.AdditionalAttributes); builder.CloseElement(); // input diff --git a/Havit.Blazor.Components.Web.Bootstrap/Forms/Internal/HxInputDateInternal.razor.cs b/Havit.Blazor.Components.Web.Bootstrap/Forms/Internal/HxInputDateInternal.razor.cs index 289267ead..76a4a0c3b 100644 --- a/Havit.Blazor.Components.Web.Bootstrap/Forms/Internal/HxInputDateInternal.razor.cs +++ b/Havit.Blazor.Components.Web.Bootstrap/Forms/Internal/HxInputDateInternal.razor.cs @@ -73,16 +73,18 @@ public partial class HxInputDateInternal : InputBase, IAsyncDisp protected DateTime GetCalendarDisplayMonthEffective => GetDateTimeFromValue(CurrentValue) ?? CalendarDisplayMonth; +#if !NET8_0_OR_GREATER private TValue previousValue; - private bool previousParsingAttemptFailed; private ValidationMessageStore validationMessageStore; +#endif private HxDropdownToggleElement hxDropdownToggleElement; private ElementReference iconWrapperElement; private IJSObjectReference jsModule; private bool firstRenderCompleted; +#if !NET8_0_OR_GREATER protected override void OnParametersSet() { base.OnParametersSet(); @@ -96,13 +98,17 @@ protected override void OnParametersSet() previousValue = Value; } } +#endif protected override string FormatValueAsString(TValue value) => HxInputDate.FormatValue(value); private void HandleValueChanged(ChangeEventArgs changeEventArgs) { +#if NET8_0_OR_GREATER + CurrentValueAsString = changeEventArgs.Value.ToString(); +#else // HandleValueChanged is used instead of TryParseValueFromString - // When TryParseValueFromString is used, invalid input is replaced by previous value. + // When TryParseValueFromString is used (pre net8), invalid input is replaced by previous value. bool parsingFailed; validationMessageStore.Clear(FieldIdentifier); @@ -123,12 +129,27 @@ private void HandleValueChanged(ChangeEventArgs changeEventArgs) EditContext.NotifyValidationStateChanged(); previousParsingAttemptFailed = parsingFailed; } - +#endif } protected override bool TryParseValueFromString(string value, out TValue result, out string validationErrorMessage) { +#if NET8_0_OR_GREATER + if (HxInputDate.TryParseDateTimeOffsetFromString(value, null, out var date)) + { + result = GetValueFromDateTimeOffset(date); + validationErrorMessage = null; + return true; + } + else + { + result = default; + validationErrorMessage = ParsingErrorMessageEffective; + return false; + } +#else throw new NotSupportedException(); +#endif } protected override async Task OnAfterRenderAsync(bool firstRender) @@ -148,11 +169,10 @@ private CalendarDateCustomizationResult GetCalendarDateCustomization(CalendarDat { return CalendarDateCustomizationProviderEffective?.Invoke(request with { Target = CalendarDateCustomizationTarget.InputDate }) ?? null; } + private async Task HandleClearClickAsync() { - CurrentValue = default; - ClearPreviousParsingMessage(); - + SetCurrentDate(null); await CloseDropdownAsync(); } @@ -164,26 +184,43 @@ private async Task CloseDropdownAsync() private async Task HandleCalendarValueChangedAsync(DateTime? date) { - CurrentValue = GetValueFromDateTimeOffset((date != null) ? new DateTimeOffset(date.Value) : null); + SetCurrentDate(date); await CloseDropdownAsync(); } protected async Task HandleCustomDateClick(DateTime value) { - CurrentValue = GetValueFromDateTimeOffset(new DateTimeOffset(DateTime.SpecifyKind(value, DateTimeKind.Unspecified), TimeSpan.Zero)); - ClearPreviousParsingMessage(); + SetCurrentDate(value); await CloseDropdownAsync(); } + protected void SetCurrentDate(DateTime? date) + { +#if NET8_0_OR_GREATER + CurrentValueAsString = date?.ToShortDateString(); // we need to trigger the logic in CurrentValueAsString setter +#else + if (date == null) + { + CurrentValue = default; + } + else + { + CurrentValue = GetValueFromDateTimeOffset(new DateTimeOffset(DateTime.SpecifyKind(date.Value, DateTimeKind.Unspecified), TimeSpan.Zero)); + } + ClearPreviousParsingMessage(); +#endif + } + +#if !NET8_0_OR_GREATER private void ClearPreviousParsingMessage() { if (previousParsingAttemptFailed) { previousParsingAttemptFailed = false; - validationMessageStore.Clear(FieldIdentifier); EditContext.NotifyValidationStateChanged(); } } +#endif private string GetNameAttributeValue() { @@ -246,7 +283,9 @@ public async ValueTask DisposeAsync() protected virtual async ValueTask DisposeAsyncCore() { +#if !NET8_0_OR_GREATER validationMessageStore?.Clear(); +#endif try { diff --git a/Havit.Blazor.Components.Web.Bootstrap/Grids/Internal/HxMultiSelectGridColumnInternal.cs b/Havit.Blazor.Components.Web.Bootstrap/Grids/Internal/HxMultiSelectGridColumnInternal.cs index 36e2b4b63..1ef23dcc1 100644 --- a/Havit.Blazor.Components.Web.Bootstrap/Grids/Internal/HxMultiSelectGridColumnInternal.cs +++ b/Havit.Blazor.Components.Web.Bootstrap/Grids/Internal/HxMultiSelectGridColumnInternal.cs @@ -29,6 +29,9 @@ protected override GridCellTemplate GetHeaderCellTemplate(GridHeaderCellContext builder.AddAttribute(103, "checked", AllDataItemsSelected); builder.AddAttribute(104, "onchange", EventCallback.Factory.Create(this, HandleSelectAllOrNoneClick)); +#if NET8_0_OR_GREATER + builder.SetUpdatesAttributeName("checked"); +#endif builder.AddEventStopPropagationAttribute(105, "onclick", true); builder.CloseElement(); // input @@ -51,6 +54,9 @@ protected override GridCellTemplate GetItemCellTemplate(TItem item) bool selected = SelectedDataItems?.Contains(item) ?? false; builder.AddAttribute(103, "checked", selected); builder.AddAttribute(104, "onchange", EventCallback.Factory.Create(this, HandleSelectDataItemClick(item, selected))); +#if NET8_0_OR_GREATER + builder.SetUpdatesAttributeName("checked"); +#endif builder.AddEventStopPropagationAttribute(105, "onclick", true); builder.CloseElement(); // input