Пользовательское связующее для модели
Вы можете реализовать собственное связующее для модели, чтобы предотвратить добавление в список пустых значений:
Просмотр:
@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; }
}
Пользовательская модель Binder:
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;
}
}