3

次のようなモデルがあるとします。

public class MyClass {
    public string Name { get; set; }
    public DateTime MyDate { get; set; }
}

Visual Studio が提供する既定の編集テンプレートは、MyDateプロパティのプレーン テキスト ボックスです。これはすべて問題ありませんが、それを月/日/年のコンポーネントに分割する必要があるとしましょう。フォームは次のようになります。

<label for="MyDate">Date:</label>
<%= Html.TextBox("MyDate-Month", Model.MyDate.Month) %>
<%= Html.TextBox("MyDate-Day", Model.MyDate.Day) %>
<%= Html.TextBox("MyDate-Year", Model.MyDate.Year) %>

UpdateModelこれが送信されると、 の定義がないため、への呼び出しは機能しませんMyDate-Month。このような状況を処理するためにプロジェクトにカスタム バインダーを追加する方法はありますか、または HTML 入力の名前が (何らかの理由で) 異なる場合はありますか?

私が見つけた 1 つの回避策は、JavaScript を使用して、フィールドを連結し、適切な名前を付けて送信する前にフォームに非表示の入力を挿入することですが、それは間違っているように感じます。

4

2 に答える 2

6

カスタムモデルバインダーをお勧めします:

using System;
using System.Globalization;
using System.Web.Mvc;

public class MyClassBinder : DefaultModelBinder
{
    protected override object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType)
    {
        var model = (MyClass)base.CreateModel(controllerContext, bindingContext, modelType);

        var day = bindingContext.ValueProvider["MyDate-Day"];
        var month = bindingContext.ValueProvider["MyDate-Month"];
        var year = bindingContext.ValueProvider["MyDate-Year"];

        var dateStr = string.Format("{0}/{1}/{2}", month.AttemptedValue, day.AttemptedValue, year.AttemptedValue);
        DateTime date;
        if (DateTime.TryParseExact(dateStr, "MM/dd/yyyy", null, DateTimeStyles.None, out date))
        {
            model.MyDate = date;
        }
        else
        {
            bindingContext.ModelState.AddModelError("MyDate", "MyDate has invalid format");
        }

        bindingContext.ModelState.SetModelValue("MyDate-Day", day);
        bindingContext.ModelState.SetModelValue("MyDate-Month", month);
        bindingContext.ModelState.SetModelValue("MyDate-Year", year);

        return model;
    }
}

これにより、コントローラーのアクションが次のように簡略化されます。

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult MyAction(MyClass myClass)
{
    if (!ModelState.IsValid)
    {
        return View(myClass);
    }
    // Do something with myClass
    return RedirectToAction("success");
}

そして、Global.asaxにバインダーを登録します。

protected void Application_Start()
{
    RegisterRoutes(RouteTable.Routes);
    ModelBinders.Binders.Add(typeof(MyClass), new MyClassBinder());
}
于 2009-07-23T19:01:52.237 に答える
4

これを処理する簡単な方法は、ValueProvider から値を手動で取得し、UpdateModel を使用してこれらのプロパティを除外するホワイト リストを使用して、日付サーバー側を構築することです。

  int month = int.Parse( this.ValueProvider["MyDate-Month"].AttemptedValue );
  int day = ...
  int year = ...

  var model = db.Models.Where( m = > m.ID == id );
  var whitelist = new string[] { "Name", "Company", ... };

  UpdateModel( model, whitelist );

  model.MyDate = new DateTime( year, month, day );

もちろん、検証/エラー処理も手動で追加する必要があります。

于 2009-07-23T18:43:11.183 に答える