在这个问题之后,我想知道是否有办法让 MVC 模型绑定器只将元素绑定到一个列表,如果有一个值来填充它们。例如,如果有一个包含三个同名输入且未输入一个值的表单,我该如何停止 MVC 绑定一个包含 3 个元素的列表,其中一个为空?
问问题
1643 次
1 回答
1
自定义模型绑定器
您可以实现自己的模型绑定器以防止将空值添加到列表中:
看法:
@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 回答