ASP.Net MVC 2 - улучшенная привязка модели для словаря <int, int> - PullRequest
1 голос
/ 26 мая 2010

В некоторых особых случаях вам понадобится список текстовых полей (для работы с n - n ассоциациями), чей идентификатор не известен до выполнения. Примерно так: http://screencast.com/t/YjIxNjUyNmU

В этом конкретном примере я хочу связать счет с некоторыми из моих «шаблонов».

в ASP.Net MVC 1 Я закодировал словарь ModelBinder, чтобы иметь чистый и интуитивно понятный HTML. Это позволило такие вещи:

// loop on the templates
foreach(ITemplate template in templates)
{
        // get the value as text
        int val;
        content.TryGetValue(template.Id, out val);
        var value = ((val > 0) ? val.ToString() : string.Empty);

        // compute the element name (for dictionary binding)
        string id = "cbts_{0}".FormatMe(template.Id);
%>
        <input type="text" id="<%= id %>" name="<%= id %>" value="<%= value %>" />
        <label for="<%= id %>"><%= template.Name %></label>
        <br />

Вот код связующего:

public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
    IDictionary<int, int> retour = new Dictionary<int, int>();

    // get the values
    var values = bindingContext.ValueProvider;
    // get the model name
    string modelname = bindingContext.ModelName + '_';
    int skip = modelname.Length;

    // loop on the keys
    foreach(string keyStr in values.Keys)
    {
        // if an element has been identified
        if(keyStr.StartsWith(modelname))
        {
            // get that key
            int key;
            if(Int32.TryParse(keyStr.Substring(skip), out key))
            {
                int value;
                if(Int32.TryParse(values[keyStr].AttemptedValue, out value))
                    retour.Add(key, value);
            }
        }
    }
    return retour;
}

При переходе на ASP.Net MVC 2 проблема заключается в том, что ValueProvider больше не является словарем. Нет способа перебрать значения для их анализа, как я.

И я не нашел другого способа сделать это (если вы знаете один, скажите мне).

Я наконец переключился на «стандартный» способ привязки словаря, но HTML уродлив, контринтуитивен (использует счетчики для циклического перебора неиндексированной коллекции ??) и все значения требуются, в отличие от поведения, которое мне нужно (и это прекрасно работало в ASP.Net MVC 1).

Это выглядит так:

int counter= 0;
// loop on the templates
foreach(ITemplate template in templates)
{
        // get the value as text
        int val;
        content.TryGetValue(template.Id, out val);
        var value = ((val > 0) ? val.ToString() : string.Empty);

        // compute the element name (for dictionary binding)
        string id = "cbts_{0}".FormatMe(template.Id);
        string dictKey = "cbts[{0}].Key".FormatMe(counter);
        string dictValue = "cbts[{0}].Value".FormatMe(counter++);
%>
        <input type="hidden" name="<%= dictKey %>" value="<%= template.Id %>" />
        <input type="text" id="<%= id %>" name="<%= dictValue %>" value="<%= value %>" />
        <label for="<%= id %>"><%= template.Name %></label>
        <br />

В контроллере мне нужно обмануть ModelState, чтобы избежать ошибок «требуется значение»:

public ActionResult Save(int? id, Dictionary<int, int> cbts)
{
    // clear all errors from the modelstate
    foreach(var value in this.ModelState.Values)
        value.Errors.Clear();

Это слишком сложно. Вскоре мне понадобится многократно использовать этот тип привязки, и, возможно, разработчик приложения поработает над приложением.

Вопрос:

  • Знаете ли вы, как сделать это лучше?

Что мне нужно, IMO, это ModelBinder для словаря, который позволяет лучше HTML и не учитывает, что все значения требуются.

Ответы [ 2 ]

2 голосов
/ 26 мая 2010

Вы абсолютно свободны продолжать использовать связыватель модели MVC 1 в MVC 2. Самое большое изменение, которое вам нужно сделать, это то, что связыватель модели не должен идти против IValueProvider, а вместо этого должен идти прямо против Request.Form,Вы можете перечислить эту коллекцию и выполнить любую логику, необходимую для вашего конкретного сценария.

Цель интерфейса IValueProvider - предоставить абстракцию, откуда поступают данные и предназначена для связующего средства общего назначения (как DefaultModelBinder).Поскольку данные не гарантируются для перечисления, сам IValueProvider не может быть IEnumerable.Но в вашем конкретном случае, когда у вас есть конкретная привязка для конкретного сценария и вы уже знаете, что данные поступают из формы, абстракция не нужна.

0 голосов
/ 04 марта 2011

Полагаю, эта статья поможет - Связыватель модели словаря в ASP.NET MVC2 и MVC3

Короче говоря, решение состоит в том, чтобы подражать MVC 1 ValueProvider в MVC 2-3.

...