在 Blazor 中本地化日期时间(和数字)

Localizing DateTime (and numbers) in Blazor

我正在开发基于最新 Core 3.1 的 Blazor 项目。

UI 文化正确显示日期和数字,如图中所示。

但是当我使用 EditForm 时,数字和日期的格式不正确。

因此 EditForm 的这段代码

<InputDate id="date" class="form-control" @bind-Value="@TaskObject.Date" />

所以在 EditForm 中它看起来像这样,这是不正确的文化格式:

但在 UI 中看起来像这样,这没关系:

作为 Blazor 的新手,我尝试在线阅读不同的内容以获取有关此问题的一些知识。

所以我已经厌倦了以下内容:

运气不好。

然后我尝试阅读 this and found this,它不适用于 Core 3.1。

我的问题是,究竟应该怎样做才能让 EditForm 像 UI 一样显示日期和数字,为什么 EditForm 会出现这种情况?

这不是 Blazor 问题,而是 type="date" 的 HTML <input> 元素的行为。

type="date" 所需的 format 是 Blazor 组件使用的 "yyyy-MM-dd"。任何其他格式均无效。

如果我们做一点测试,我们可以验证这不是 Blazor 问题。

@page "/dates"
@using System.Globalization
<h3>Date</h3>
<p>@_dateString</p>
<input type="date" value="@_dateString" />
@code {
    private string _dateString;

    protected override void OnInitialized()
    {
        // using en-US culture
        // this is what InputDate component does
        _dateString = DateTime.Now.ToString("yyyy-MM-dd", CultureInfo.InvariantCulture);
    }
}

_dateString 输出 2019-12-30<input> 中显示的日期是 30/12/2019

有关 type=date 的详细信息可在 here 中找到。在“值”部分中,有一条说明如下:

The displayed date format will differ from the actual value — the displayed date is formatted based on the locale of the user's browser, but the parsed value is always formatted yyyy-mm-dd.

因此格式固定为用户浏览器的区域设置。

Why this happen for EditForm

内置的InputDate/InputNumber被设计为Culture-Invariant组件。参见 source code of InputDate and InputNumber

What should exactly be done to make EditForm show date and number like the of UI,

我认为我们可以创建自定义 InputDate<TValue> 实现。然而,我错了。根据 MDN:

The displayed date is formatted based on the locale of the user's browser, but the parsed value is always formatted yyyy-mm-dd..

即使我们获得了支持当前 CultureInfo 的自定义 InputDate<TValue> 实现,我们仍然需要一些 js/css 来显示正确的格式。 IMO,没有标准的方法来实现这个。另见 this thread on SO.

我建议使用这个组件 https://blazorrepl.com/repl/wbambCPv20P0pX1h21

编辑: 如果 link 不起作用,这里是代码:

<style>
    #myInput[type="date"] {
        margin-top: 3px;
        border: 0;
        position: absolute;
        width: 24px;
        height: 24px;
    }

        #myInput[type="date"]::-webkit-inner-spin-button {
            display: none;
        }

        #myInput[type="date"]::-webkit-calendar-picker-indicator {
            margin: 0;
            position: absolute;
        }

    #myInput[type=date]::-webkit-datetime-edit,
    #myInput[type=date]::-webkit-datetime-edit-fields-wrapper {
        -webkit-appearance: none;
        display: none;
        margin: 0;
        padding: 0;
    }
</style>
<input value="@this.Value.ToString(this.Format)" @onchange="this.DateChangedAsync" class="@Class" style="display:inline-block;margin-right: -38px;" />
<input id="myInput" type="date" value="@Value" @onchange="this.DateChangedAsync" style="display:inline-block; " />

@code {
    [Parameter]
        public string Format { get; set; }

        [Parameter]
        public DateTime Value { get; set; }

        [Parameter]
        public EventCallback<DateTime> ValueChanged { get; set; }

        [Parameter]
        public string Class { get; set; }

        protected override void OnParametersSet()
        {
            if (string.IsNullOrWhiteSpace(Format))
            {
                this.Format = "dd/MM/yyyy";
            }
        }

        private async Task DateChangedAsync(ChangeEventArgs args)
        {
            string text = args.Value.ToString();

            if (string.IsNullOrWhiteSpace(text))
            {
                return;
            }

            this.Value = DateTime.Parse(text);
            await this.ValueChanged.InvokeAsync(this.Value);
        }
}