ASP.NET MVC5 アプリで日付(DateTime 型)と通貨(Decimal 型)を表示し、編集してデータベースを更新する場合、どのように書式設定を行うのが良いかということについて書きます。
上の画像は DisplayFor と TextBoxFor を上下に並べて表示していますが、その「契約日」と「価格」に示したように、
-
DisplayFor 等を使った表示の場合のみ書式設定を行い、
-
テキストボックスに値を表示する場合は書式設定しない。または、"{0:F0}" のような書式設定に留めパースできない文字は含めないようにする。
・・・のがよさそうです。
スキャフォールディング機能を使って CRUD 可能なアプリを作ると Index (レコード一覧), Create, Delete, Edit, Details というアクションメソッドとそれに対応するビューが生成されますが、Index, Delete, Details を上記 (1) で、Create, Edit を上記 (2) で表示するということです。
テキストボックスに表示する文字列も 2019年2月4日 とか ¥1,000 のように表示することはできますが、クライアント側での検証を無効にしてサーバーに POST したとしても、DateTime 型や Decimal 型にパースできないので結局モデルバインディングの際の検証が通りません。
どうしてもテキストボックスに表示する文字列も 2019年2月4日 とか ¥1,000 のようにしたいということであれば、モデルのプロパティも含めて全て String 型として扱い、検証は正規表現のみを使って行うということも考えられますが、データベースの型が datetime とか money でしょうから、サーバー側での取り扱いを考えると現実的ではなさそうです。
それに、ユーザーとしても、編集する際にいちいち ¥ とか , を入力するのは煩わしいはずで、喜んではくれないのでは?
上の画像のように表示するための方法ですが、DisplayFor での表示の書式はモデルのプロパティに DisplayFormatAttribute を付与して設定し、テキストボックスには TextBoxFor を使ってその第 2 引数に "{0:yyyy/MM/dd}"、"{0:F0}" などの書式を設定するのがよさそうです。
EditorFor を使うと書式が自由に設定できないし(DisplayFormatAttribute の設定と同じでよければ可能ですが)、レンダリングされる html ソースの input 要素の type 属性が問題になることがありますので使う場合は要注意です。
具体的には以下のようにします。
Model
public class PurchaseRecord
{
[Display(Name = "ID")]
[Required(ErrorMessage = "{0} は必須")]
[RegularExpression(@"^\d{1,5}$",
ErrorMessage = "数字 1 ~ 5 文字")]
public int ID { get; set; }
[Display(Name = "契約日")]
[Required(ErrorMessage = "{0} は必須")]
[RegularExpression(
@"^\d{4}/\d{2}/\d{2}( \d{1,2}:\d{2}:\d{2})?$",
ErrorMessage = "yyyy/MM/dd 形式")]
[DisplayFormat(DataFormatString = "{0:yyyy年M月d日}")]
public DateTime ContractDate { get; set; }
[Display(Name = "価格")]
[Required(ErrorMessage = "{0} は必須")]
[RegularExpression(@"^\d{1,5}$",
ErrorMessage = "数字 1 ~ 5 文字")]
[DisplayFormat(DataFormatString = "{0:C0}")]
public decimal Price { get; set; }
}
View(一部の抜粋)
<div class="form-group">
@Html.LabelFor(model => model.ID,
htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.DisplayFor(model => model.ID)
@Html.EditorFor(model => model.ID,
new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.ID,
"", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.ContractDate,
htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.DisplayFor(model => model.ContractDate)
@Html.TextBoxFor(model => model.ContractDate,
"{0:yyyy/MM/dd}", new { @class = "form-control" })
@Html.ValidationMessageFor(model => model.ContractDate,
"", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.Price,
htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.DisplayFor(model => model.Price)
@Html.TextBoxFor(model => model.Price,
"{0:F0}",new { @class = "form-control" })
@Html.ValidationMessageFor(model => model.Price,
"", new { @class = "text-danger" })
</div>
</div>
あと、オマケの話ですが、ASP.NET Web Forms アプリで使う GridView などで書式設定する際も同様なことはできます。以下の画像を見てください。
赤枠で囲った部分は[編集]ボタンをクリックして編集モードにしたテキストボックスですが、他の行との違いを見てください。