この質問に続いて、MVCモデルバインダーに要素をリストにバインドさせる値がある場合にのみ要素をバインドする方法があるかどうか疑問に思っていました。たとえば、同じ名前の 3 つの入力を持つフォームがあり、1 つの値が入力されていない場合、3 つの要素を持つリストの MVC バインドを停止するにはどうすればよいですか?そのうちの 1 つが null です。
1643 次
1 に答える
1
カスタムモデルバインダー
独自のモデル バインダーを実装して、null 値がリストに追加されないようにすることができます。
意見:
@model MvcApplication10.Models.IndexModel
<h2>Index</h2>
@using (Html.BeginForm())
{
<ul>
<li>Name: @Html.EditorFor(m => m.Name[0])</li>
<li>Name: @Html.EditorFor(m => m.Name[1])</li>
<li>Name: @Html.EditorFor(m => m.Name[2])</li>
</ul>
<input type="submit" value="submit" />
}
コントローラ:
public class HomeController : Controller
{
public ViewResult Index()
{
return View();
}
[HttpPost]
public ActionResult Index(IndexModel myIndex)
{
if (ModelState.IsValid)
{
return RedirectToAction("NextPage");
}
else
{
return View();
}
}
}
モデル:
public class IndexModel
{
public List<string> Name { get; set; }
}
カスタム モデル バインダー:
public class IndexModelBinder : IModelBinder
{
public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
bool hasPrefix = bindingContext.ValueProvider.ContainsPrefix(bindingContext.ModelName);
string searchPrefix = (hasPrefix) ? bindingContext.ModelName + "." : "";
List<string> valueList = new List<string>();
int index = 0;
string value;
do
{
value = GetValue(bindingContext, searchPrefix, "Name[" + index + "]");
if (!string.IsNullOrEmpty(value))
{
valueList.Add(value);
}
index++;
} while (value != null); //a null value indicates that the Name[index] field does not exist where as a "" value indicates that no value was provided.
if (valueList.Count > 0)
{
//obtain the model object. Note: If UpdateModel() method was called the model will have been passed via the binding context, otherwise create our own.
IndexModel model = (IndexModel)bindingContext.Model ?? new IndexModel();
model.Name = valueList;
return model;
}
//No model to return as no values were provided.
return null;
}
private string GetValue(ModelBindingContext context, string prefix, string key)
{
ValueProviderResult vpr = context.ValueProvider.GetValue(prefix + key);
return vpr == null ? null : vpr.AttemptedValue;
}
}
Application_Start()
(global.asax)にモデル バインダーを登録する必要があります。
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
//this will use your custom model binder any time you add the IndexModel to an action or use the UpdateModel() method.
ModelBinders.Binders.Add(typeof(IndexModel), new IndexModelBinder());
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
}
カスタム検証属性
または、カスタム属性を使用して、すべての値が設定されていることを検証できます。
意見:
@model MvcApplication3.Models.IndexModel
<h2>Index</h2>
@using (Html.BeginForm())
{
@Html.ValidationMessageFor(m => m.Name)
<ul>
<li>Name: @Html.EditorFor(m => m.Name[0])</li>
<li>Name: @Html.EditorFor(m => m.Name[1])</li>
<li>Name: @Html.EditorFor(m => m.Name[2])</li>
</ul>
<input type="submit" value="submit" />
}
コントローラ:
上で定義したものと同じコントローラーを使用します。
モデル:
public class IndexModel
{
[AllRequired(ErrorMessage="Please enter all required names")]
public List<string> Name { get; set; }
}
カスタム属性:
public class AllRequiredAttribute : ValidationAttribute
{
public override bool IsValid(object value)
{
bool nullFound = false;
if (value != null && value is List<string>)
{
List<string> list = (List<string>)value;
int index = 0;
while (index < list.Count && !nullFound)
{
if (string.IsNullOrEmpty(list[index]))
{
nullFound = true;
}
index++;
}
}
return !nullFound;
}
}
于 2011-12-08T12:37:26.960 に答える