ASP.Net MVC 2 - 更好的ModelBinding for Dictionary <int,int =“”> </int,>

时间:2010-05-26 08:20:32

标签: asp.net-mvc-2 dictionary modelbinders duplicates

在某些特殊情况下,您需要一个文本框列表(用于处理n-n个关联),其id在运行时之前是未知的。 这样的事情:http://screencast.com/t/YjIxNjUyNmU

在那个特定的样本中,我希望将计数与我的一些“模板”相关联。

ASP.Net MVC 1 中,我编写了一个Dictionary 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 个答案:

答案 0 :(得分:2)

你可以继续在MVC 2中继续使用你的MVC 1模型绑定器。你必须做的最大的改变是你的模型绑定器不应该违反IValueProvider,而应该直接针对Request.Form 。您可以枚举该集合并执行特定方案所需的任何逻辑。

IValueProvider接口的目的是提供数据来源的抽象,并用于通用绑定器(如DefaultModelBinder)。由于数据不能保证可枚举,因此IValueProvider本身不能是IEnumerable。但是在您的特定情况下,如果您有特定场景的特定绑定器并且已经知道数据来自表单,则抽象是不必要的。

答案 1 :(得分:0)

我相信这篇文章会有所帮助 - Dictionary Model Binder in ASP.NET MVC2 and MVC3

简而言之,解决方案是在MVC 2-3中模仿MVC 1 ValueProvider。