Как получить MVC Model Binder только для связывания ненулевых значений для списка? - PullRequest
1 голос
/ 08 декабря 2011

После этого вопроса Мне было интересно, есть ли способ связывания модели MVC только связывать элементы со списком, если есть значение для их заполнения. Например, если у вас есть форма с тремя входами с одинаковым именем и одно значение не введено, как мне остановить привязку MVC к списку, содержащему 3 элемента, один из которых равен нулю?

1 Ответ

1 голос
/ 08 декабря 2011

Пользовательское связующее для модели

Вы можете реализовать собственное связующее для модели, чтобы предотвратить добавление в список пустых значений:

Просмотр:

@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;
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...