Asp.net mvc 4でdatetimeの形式を強制するにはどうすればよいですか?表示モードでは必要に応じて表示されますが、編集モデルでは表示されません。 displayforとeditorforを使用し、dataformatstring = "{0:dd/MM/yyyy}"でapplyformatineditmode = trueを使用しています。
強制する方法がわかりません。日付をデフォルトではなくdd/MM/yyyyとして入力する必要があります。
詳細:私のviewmodelはこのようなものです
[DisplayName("date of birth")]
[DataType(DataType.Date)]
[DisplayFormat(DataFormatString = "{0:dd/MM/yyyy}", ApplyFormatInEditMode = true)]
public DateTime? Birth { get; set; }
ビューでは@Html.DisplayFor(m=>m.Birth)
を使用しますが、これは期待どおりに機能し(フォーマットが表示されます)、@Html.EditorFor(m=>m.Birth)
を使用して日付を入力しますが、13/12/2000のようなものを入力しようとするとエラーで失敗します有効な日付ではないこと(2000年12月13日と2000年12月13日は期待どおりに機能していますが、dd/MM/yyyyが必要です)。
カスタムmodelbinderはapplication_start()で呼び出されますb/c他にどこにあるかわかりません。
<globalization/>
を使用して、culture="ro-RO", uiCulture="ro"
およびdd/MM/yyyyを提供するその他のカルチャで試しました。 application_start()でスレッドごとに設定しようとしました(これを行う方法については、ここに多くの例があります)
この質問はすべて読んでください:クライアントの検証がない限り、Darin Dimitrovの答えは機能すると思われます。別のアプローチは、クライアント側の検証を含むカスタム検証を使用することです。アプリケーション全体を再作成する前にこれを見つけてうれしいです。
ああ、今では明らかです。値のバインドに問題があるようです。ビューに表示するのではありません。確かに、それはデフォルトのモデルバインダーの欠点です。モデルの[DisplayFormat]
属性を考慮に入れたカスタムのものを作成して使用できます。このようなカスタムモデルバインダーをここに示しました: https://stackoverflow.com/a/7836093/29407
どうやらまだいくつかの問題が残っています。 ASP.NET MVC 3と4 RCの両方で完全に機能する完全なセットアップを次に示します。
型:
public class MyViewModel
{
[DisplayName("date of birth")]
[DataType(DataType.Date)]
[DisplayFormat(DataFormatString = "{0:dd/MM/yyyy}", ApplyFormatInEditMode = true)]
public DateTime? Birth { get; set; }
}
コントローラ:
public class HomeController : Controller
{
public ActionResult Index()
{
return View(new MyViewModel
{
Birth = DateTime.Now
});
}
[HttpPost]
public ActionResult Index(MyViewModel model)
{
return View(model);
}
}
見る:
@model MyViewModel
@using (Html.BeginForm())
{
@Html.LabelFor(x => x.Birth)
@Html.EditorFor(x => x.Birth)
@Html.ValidationMessageFor(x => x.Birth)
<button type="submit">OK</button>
}
Application_Start
でのカスタムモデルバインダーの登録:
ModelBinders.Binders.Add(typeof(DateTime?), new MyDateTimeModelBinder());
カスタムモデルバインダー自体:
public class MyDateTimeModelBinder : DefaultModelBinder
{
public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
var displayFormat = bindingContext.ModelMetadata.DisplayFormatString;
var value = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
if (!string.IsNullOrEmpty(displayFormat) && value != null)
{
DateTime date;
displayFormat = displayFormat.Replace("{0:", string.Empty).Replace("}", string.Empty);
// use the format specified in the DisplayFormat attribute to parse the date
if (DateTime.TryParseExact(value.AttemptedValue, displayFormat, CultureInfo.InvariantCulture, DateTimeStyles.None, out date))
{
return date;
}
else
{
bindingContext.ModelState.AddModelError(
bindingContext.ModelName,
string.Format("{0} is an invalid date format", value.AttemptedValue)
);
}
}
return base.BindModel(controllerContext, bindingContext);
}
}
これで、web.config(<globalization>
要素)または現在のスレッドカルチャで設定したカルチャに関係なく、カスタムモデルバインダーはDisplayFormat
属性の日付形式を使用して、null許容日付を解析します。
クライアント検証の問題は、jquery.validate.unobtrusive.min.jsのMVCバグ(MVC 5でも)が原因で発生する可能性がありますしない任意の方法で日付/日付時刻形式を受け入れます。残念ながら、手動で解決する必要があります。
私の最終的に機能するソリューション:
$(function () {
$.validator.methods.date = function (value, element) {
return this.optional(element) || moment(value, "DD.MM.YYYY", true).isValid();
}
});
前に含める必要があります:
@Scripts.Render("~/Scripts/jquery-3.1.1.js")
@Scripts.Render("~/Scripts/jquery.validate.min.js")
@Scripts.Render("~/Scripts/jquery.validate.unobtrusive.min.js")
@Scripts.Render("~/Scripts/moment.js")
Moment.jsをインストールするには、次を使用できます。
Install-Package Moment.js
Darinに感謝します。私にとって、createメソッドに投稿できるようになったのは、BindModelコードを次のように変更した後でのみ機能しました。
public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
var displayFormat = bindingContext.ModelMetadata.DisplayFormatString;
var value = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
if (!string.IsNullOrEmpty(displayFormat) && value != null)
{
DateTime date;
displayFormat = displayFormat.Replace("{0:", string.Empty).Replace("}", string.Empty);
// use the format specified in the DisplayFormat attribute to parse the date
if (DateTime.TryParse(value.AttemptedValue, CultureInfo.GetCultureInfo("en-GB"), DateTimeStyles.None, out date))
{
return date;
}
else
{
bindingContext.ModelState.AddModelError(
bindingContext.ModelName,
string.Format("{0} is an invalid date format", value.AttemptedValue)
);
}
}
return base.BindModel(controllerContext, bindingContext);
}
これが他の誰かに役立つことを願っています...