個人的に私はこれが好きではありません:
enum AnswerType
{
String,
DateTime
}
私は .NET 型システムを使用することを好みます。別のデザインを提案させてください。いつものように、ビュー モデルを定義することから始めます。
public abstract class AnswerViewModel
{
public string Type
{
get { return GetType().FullName; }
}
}
public class StringAnswer : AnswerViewModel
{
[Required]
public string Value { get; set; }
}
public class DateAnswer : AnswerViewModel
{
[Required]
public DateTime? Value { get; set; }
}
public class QuestionViewModel
{
public int Id { get; set; }
public string Caption { get; set; }
public AnswerViewModel Answer { get; set; }
}
次にコントローラー:
public class HomeController : Controller
{
public ActionResult Index()
{
var model = new[]
{
new QuestionViewModel
{
Id = 1,
Caption = "What is your favorite color?",
Answer = new StringAnswer()
},
new QuestionViewModel
{
Id = 1,
Caption = "What is your birth date?",
Answer = new DateAnswer()
},
};
return View(model);
}
[HttpPost]
public ActionResult Index(IEnumerable<QuestionViewModel> questions)
{
// process the answers. Thanks to our custom model binder
// (see below) here you will get the model properly populated
...
}
}
次に、メインIndex.cshtml
ビュー:
@model QuestionViewModel[]
@using (Html.BeginForm())
{
<ul>
@for (int i = 0; i < Model.Length; i++)
{
@Html.HiddenFor(x => x[i].Answer.Type)
@Html.HiddenFor(x => x[i].Id)
<li>
@Html.DisplayFor(x => x[i].Caption)
@Html.EditorFor(x => x[i].Answer)
</li>
}
</ul>
<input type="submit" value="OK" />
}
これで、回答用のエディター テンプレートを使用できるようになりました。
~/Views/Home/EditorTemplates/StringAnswer.cshtml
:
@model StringAnswer
<div>It's a string answer</div>
@Html.EditorFor(x => x.Value)
@Html.ValidationMessageFor(x => x.Value)
~/Views/Home/EditorTemplates/DateAnswer.cshtml
:
@model DateAnswer
<div>It's a date answer</div>
@Html.EditorFor(x => x.Value)
@Html.ValidationMessageFor(x => x.Value)
最後のピースは、回答用のカスタム モデル バインダーです。
public class AnswerModelBinder : DefaultModelBinder
{
protected override object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType)
{
var typeValue = bindingContext.ValueProvider.GetValue(bindingContext.ModelName + ".Type");
var type = Type.GetType(typeValue.AttemptedValue, true);
var model = Activator.CreateInstance(type);
bindingContext.ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => model, type);
return model;
}
}
に登録されApplication_Start
ます:
ModelBinders.Binders.Add(typeof(AnswerViewModel), new AnswerModelBinder());