1

在这个问题之后,我想知道是否有办法让 MVC 模型绑定器只将元素绑定到一个列表,如果有一个值来填充它们。例如,如果有一个包含三个同名输入且未输入一个值的表单,我该如何停止 MVC 绑定一个包含 3 个元素的列表,其中一个为空?

4

1 回答 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 回答