如何将文本框绑定到日期时间字段但仅显示其日期部分(在 ASP.MVC 中)?

How to bind a textbox to a datetime field but display only its date part (in ASP.MVC)?

我有一个文本框绑定到 DateTime 模型字段的视图。

观点:

@Html.TextBoxFor(model => model.StartDate, new { @class = "datepicker", id = "startDate" })

型号:

[Required(ErrorMessageResourceType = typeof(Resources.ValidationMessages), ErrorMessageResourceName = "GeneralRequired")]
[DisplayFormat(DataFormatString = "{0:dd-MM-yyyy}", ApplyFormatInEditMode = true)]
[DataType(DataType.Date)]
[Display(Name = "StartDate", ResourceType = typeof(Resources.Something))]
public DateTime? StartDate { get; set; }

View 使用 jQuery 日期选择器来处理日期输入。 Jquery 只生成日期,但据我所知,C# 中没有唯一的日期类型。

我也使用自定义 DateTime 模型联编程序,但它对 post 它的代码来说太大了 (tl;dr ;))。

当用户在文本框中输入例如 15-01-2015,然后 post 将其转换为模型活页夹正确转换的方法(转换为 15-01-2015 12:00)。问题是当验证被触发时,因为表单上有两个日期时间字段,如果用户只输入其中一个,则操作方法 returns 查看带有验证消息。已经进入的字段显然应该仍然被填充。问题是,当控制器的操作方法 returns 查看时,它会将日期时间放入文本框中,而不仅仅是日期。

有没有什么方法可以只将日期而不是日期和时间传递给视图中的绑定字段?或者可能保留字段绑定但仅在文本框中显示 value.Date?

编辑:

我尝试应用 Hugo Delsing 的解决方案,但遇到了下一个问题。基本上,我们将为模型的 DateTime 字段使用 EditorTemplate。 DateTime.cshtml 看起来如下:

@model System.DateTime?
@if (Model == null)
{
    @Html.TextBox(
   string.Empty,
   "",
   new { @class = "datepicker", @type = "text" })
}
else
{
    @Html.TextBox(
   string.Empty,
   Model.ToString("dd-MM-yyyy"),
   new { @class = "datepicker", @type = "text" })
}

据我了解,问题出现在行

Model.ToString("dd-MM-yyyy")

因为抛出的错误是

Shared\EditorTemplates\DateTime.cshtml(13): error CS1501: No overload for method 'ToString' takes 1 arguments

据我了解,else 总是被评估,对吗? 有什么解决方案可以在不将 if 语句移动到主视图并构建类似这样的东西的情况下实现我想要的吗?

@if(model.StartDate.HasValue)
{
   @Html.EditorFor(model => model.StartDate, "TemplateFirst")
}
else
{
   @Html.EditorFor(model => model.StartDate, "TemplateSecond")
}

让我正常工作的唯一方法是创建一个新的 EditorTemplate

~/Views/Shared/EditorTemplates 中创建一个名为 DateTime.cshtml 的视图,并将以下内容放入其中。

@model System.DateTime?
@{
    var val = "";
    if (Model != null)
    {
        val = ((DateTime)Model).ToString("dd-MM-yyyy");
    }
}
@Html.TextBox(
   string.Empty, 
   val,
   new { @class="datepicker", @type = "text"})

现在,如果您调用默认的编辑器模板,它将起作用并始终显示 datepicker 日期。

<div class="editor-container">
    <div class="editor-label">
        @Html.LabelFor(model => model.StartDate)
    </div>
    <div class="editor-field">
        @Html.EditorFor(model => model.StartDate)
        @Html.ValidationMessageFor(model => model.StartDate)
    </div>
</div>

正如 Stephen Muecke 指出的那样,@type = "text" 并不是真正需要的。这是默认设置。您可以 add/change 到 date 以触发 HTML5 日期选择器。请记住,它可能会在 'MM-dd-yyyy' 中显示 HTML5 日期选择器,然后无法验证该值。

如果您使用jQuery日期选择器,那么您需要在插件代码和TextBoxFor()方法

中格式化日期
@Html.TextBoxFor(m => m.StartDate, "{0:dd-MM-yyyy}", new { @class = "datepicker" })

和脚本

$('.datepicker').datepicker({ dateFormat: 'dd-mm-yy' })

旁注:您不需要设置 id 属性(助手会为您添加 id="StartDate"

另请注意,使用 TextBoxFor() 时,属性 上不需要 [DisplayFormat(DataFormatString = "{0:dd-MM-yyyy}", ApplyFormatInEditMode = true)][DataType(DataType.Date)]。只有在使用 @Html.EditorFor() 时才会考虑这些属性,并导致生成 <input type="date" ...>,这将呈现浏览器 HTML5 日期选择器。无论如何,它需要是 DataFormatString = "{0:yyyy-MM-dd}"(ISO 格式)才能正确绑定。请注意 type="date" 仅在某些现代浏览器中受支持,而在 FireFox 中根本不支持)

DateTime 的自定义 EditorTemplate 不是必需的,但如果您要这样做,那只是

@model System.DateTime?
@Html.TextBoxFor(m => m.StartDate, "{0:dd-MM-yyyy}", new { @class = "datepicker" })

根据已接受的答案,无需测试 null。这个解决方案是不灵活的,因为你不能传递 html 属性(没有一些修改就可以按照 传递 additionViewData

您还提到使用自定义 ModelBinder,它 太大 post。目前还不清楚你为什么需要这个。如果您将服务器区域性设置为接受该格式,则不需要它,例如

<system.web>
  <globalization culture="en-AU" uiCulture="en-AU"/>

但无论如何,应该不会超过几行代码。 Refer this example

最后,如果你包含 @Html.ValidationMessageFor(m => m.StartDate) 那么你可以使用 Globalisation Nuget Package (globalize.js) 或者你可以重写 $.validator.methods.date 方法,但是因为你可以设置选项这样作为 jQuery 日期选择器中的最小和最大日期,可能没有必要使用 ValidationMessageFor