MVC 3 中可以将模型绑定到具有非顺序索引的列表吗?

发布于 2024-11-02 10:44:10 字数 1113 浏览 6 评论 0 原文

我正在关注 http:// 上的信息haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx 来自 Phil Haack

他谈论非顺序索引:

<form method="post" action="/Home/Create">

<input type="hidden" name="products.Index" value="cold" />
<input type="text" name="products[cold].Name" value="Beer" />
<input type="text" name="products[cold].Price" value="7.32" />

<input type="hidden" name="products.Index" value="123" />
<input type="text" name="products[123].Name" value="Chips" />
<input type="text" name="products[123].Price" value="2.23" />

<input type="hidden" name="products.Index" value="caliente" />
<input type="text" name="products[caliente].Name" value="Salsa" />
<input type="text" name="products[caliente].Price" value="1.23" />

<input type="submit" />
</form>

当您使用模型绑定时,这在 MVC3 中是否可能与 TextBoxFor?
这是使用顺序索引的方法:

@Html.TextBoxFor(m => m[i].Value)

如果不可能,如果我的索引不是顺序的,我还能做些什么吗?

I'm following the info on http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx from Phil Haack

He talks about Non-Sequential indices:

<form method="post" action="/Home/Create">

<input type="hidden" name="products.Index" value="cold" />
<input type="text" name="products[cold].Name" value="Beer" />
<input type="text" name="products[cold].Price" value="7.32" />

<input type="hidden" name="products.Index" value="123" />
<input type="text" name="products[123].Name" value="Chips" />
<input type="text" name="products[123].Price" value="2.23" />

<input type="hidden" name="products.Index" value="caliente" />
<input type="text" name="products[caliente].Name" value="Salsa" />
<input type="text" name="products[caliente].Price" value="1.23" />

<input type="submit" />
</form>

Is this possible in MVC3 when you use model binding with TextBoxFor?
This is the way to do it with sequentiel indices:

@Html.TextBoxFor(m => m[i].Value)

If it's not possible, is their anything else I can do if my indices will not be sequential?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

眼趣 2024-11-09 10:44:10

AFAI 了解非顺序索引技术需要为每个索引值添加隐藏字段。我非常确定 Html.TextBoxFor 助手本身不会生成任何其他隐藏字段。也许您可以通过手动添加具有非顺序索引的隐藏字段来实现此目的。

AFAI understand the non-sequential indices technique would require to add hidden fields for each index value. I'm quite sure that the Html.TextBoxFor helper itself does not generate any additional hidden fields. Probably you could achieve this by manually adding the hidden fields with the non-sequential indices.

迷鸟归林 2024-11-09 10:44:10

我尝试了这个,但无法让它与 textboxfor 一起使用。我使用文本框并指定了名称。

<form method="post" action="/Home/Create">
@{var index = Guid.NewGuid();}
@Html.Textbox("products["+index +"].Name",Beer)
@Html.Textbox("products["+index +"].Price",7.32)
.
.
.
<input type="submit" />
</form>

MVC 3.0 不需要隐藏索引。

如果这不起作用,请告诉我,我有办法做到这一点,我只是从我的脑海中想到这一点。

I tried this and I couldn't get it to work with textboxfor. I used Textbox and specified the name.

<form method="post" action="/Home/Create">
@{var index = Guid.NewGuid();}
@Html.Textbox("products["+index +"].Name",Beer)
@Html.Textbox("products["+index +"].Price",7.32)
.
.
.
<input type="submit" />
</form>

You don't need a hidden index for MVC 3.0.

Let me know if this does not work I have a way of doing this, I'm just taking this from the top of my head.

攀登最高峰 2024-11-09 10:44:10

为了不扰乱您的视图,我发现执行此操作的最简单方法是遵循此扩展:BeginCollectionItem

完整的项目在这里: https://github.com/danludwig/BeginCollectionItem

但据我所知你只需要这个类:

public static class HtmlPrefixScopeExtensions
    {
        private const string idsToReuseKey = "__htmlPrefixScopeExtensions_IdsToReuse_";

        public static IDisposable BeginCollectionItem(this HtmlHelper html, string collectionName)
        {
            var idsToReuse = GetIdsToReuse(html.ViewContext.HttpContext, collectionName);
            string itemIndex = idsToReuse.Count > 0 ? idsToReuse.Dequeue() : Guid.NewGuid().ToString();

            // autocomplete="off" is needed to work around a very annoying Chrome behaviour whereby it reuses old values after the user clicks "Back", which causes the xyz.index and xyz[...] values to get out of sync.
            html.ViewContext.Writer.WriteLine(string.Format("<input type=\"hidden\" name=\"{0}.index\" autocomplete=\"off\" value=\"{1}\" />", collectionName, html.Encode(itemIndex)));

            return BeginHtmlFieldPrefixScope(html, string.Format("{0}[{1}]", collectionName, itemIndex));
        }

        public static IDisposable BeginHtmlFieldPrefixScope(this HtmlHelper html, string htmlFieldPrefix)
        {
            return new HtmlFieldPrefixScope(html.ViewData.TemplateInfo, htmlFieldPrefix);
        }

        private static Queue<string> GetIdsToReuse(HttpContextBase httpContext, string collectionName)
        {
            // We need to use the same sequence of IDs following a server-side validation failure,  
            // otherwise the framework won't render the validation error messages next to each item.
            string key = idsToReuseKey + collectionName;
            var queue = (Queue<string>)httpContext.Items[key];
            if (queue == null) {
                httpContext.Items[key] = queue = new Queue<string>();
                var previouslyUsedIds = httpContext.Request[collectionName + ".index"];
                if (!string.IsNullOrEmpty(previouslyUsedIds))
                    foreach (string previouslyUsedId in previouslyUsedIds.Split(','))
                        queue.Enqueue(previouslyUsedId);
            }
            return queue;
        }

        private class HtmlFieldPrefixScope : IDisposable
        {
            private readonly TemplateInfo templateInfo;
            private readonly string previousHtmlFieldPrefix;

            public HtmlFieldPrefixScope(TemplateInfo templateInfo, string htmlFieldPrefix)
            {
                this.templateInfo = templateInfo;

                previousHtmlFieldPrefix = templateInfo.HtmlFieldPrefix;
                templateInfo.HtmlFieldPrefix = htmlFieldPrefix;
            }

            public void Dispose()
            {
                templateInfo.HtmlFieldPrefix = previousHtmlFieldPrefix;
            }
        }
    }

如何在视图中使用它:

<form method="post" action="/Home/Create">
    @foreach (var item in Model.Products) {    
        @using (Html.BeginCollectionItem("Products"))
        { 
            @Html.TextBoxFor(item => item.Name)
            @Html.TextBoxFor(item => item.Price)            
        }
     } 
         ...
         ...
</form>

我认为这比弄乱视图中的索引更干净......
这是逐步解释如何操作的帖子: http://blog.stevensanderson.com/2010/01/28/editing-a-variable-length-list-aspnet-mvc-2-style/

Nuget 包: http://www.nuget.org/packages/BeginCollectionItem/

To not messing with your view, the easiest way I found to do this is following this extension: BeginCollectionItem.

The complete project is here: https://github.com/danludwig/BeginCollectionItem

But AFAIK you only need this class:

public static class HtmlPrefixScopeExtensions
    {
        private const string idsToReuseKey = "__htmlPrefixScopeExtensions_IdsToReuse_";

        public static IDisposable BeginCollectionItem(this HtmlHelper html, string collectionName)
        {
            var idsToReuse = GetIdsToReuse(html.ViewContext.HttpContext, collectionName);
            string itemIndex = idsToReuse.Count > 0 ? idsToReuse.Dequeue() : Guid.NewGuid().ToString();

            // autocomplete="off" is needed to work around a very annoying Chrome behaviour whereby it reuses old values after the user clicks "Back", which causes the xyz.index and xyz[...] values to get out of sync.
            html.ViewContext.Writer.WriteLine(string.Format("<input type=\"hidden\" name=\"{0}.index\" autocomplete=\"off\" value=\"{1}\" />", collectionName, html.Encode(itemIndex)));

            return BeginHtmlFieldPrefixScope(html, string.Format("{0}[{1}]", collectionName, itemIndex));
        }

        public static IDisposable BeginHtmlFieldPrefixScope(this HtmlHelper html, string htmlFieldPrefix)
        {
            return new HtmlFieldPrefixScope(html.ViewData.TemplateInfo, htmlFieldPrefix);
        }

        private static Queue<string> GetIdsToReuse(HttpContextBase httpContext, string collectionName)
        {
            // We need to use the same sequence of IDs following a server-side validation failure,  
            // otherwise the framework won't render the validation error messages next to each item.
            string key = idsToReuseKey + collectionName;
            var queue = (Queue<string>)httpContext.Items[key];
            if (queue == null) {
                httpContext.Items[key] = queue = new Queue<string>();
                var previouslyUsedIds = httpContext.Request[collectionName + ".index"];
                if (!string.IsNullOrEmpty(previouslyUsedIds))
                    foreach (string previouslyUsedId in previouslyUsedIds.Split(','))
                        queue.Enqueue(previouslyUsedId);
            }
            return queue;
        }

        private class HtmlFieldPrefixScope : IDisposable
        {
            private readonly TemplateInfo templateInfo;
            private readonly string previousHtmlFieldPrefix;

            public HtmlFieldPrefixScope(TemplateInfo templateInfo, string htmlFieldPrefix)
            {
                this.templateInfo = templateInfo;

                previousHtmlFieldPrefix = templateInfo.HtmlFieldPrefix;
                templateInfo.HtmlFieldPrefix = htmlFieldPrefix;
            }

            public void Dispose()
            {
                templateInfo.HtmlFieldPrefix = previousHtmlFieldPrefix;
            }
        }
    }

How to use it in your Views:

<form method="post" action="/Home/Create">
    @foreach (var item in Model.Products) {    
        @using (Html.BeginCollectionItem("Products"))
        { 
            @Html.TextBoxFor(item => item.Name)
            @Html.TextBoxFor(item => item.Price)            
        }
     } 
         ...
         ...
</form>

I think this is cleaner than messing with the indexs in you views...
Here is the post that explains how to do it step by step: http://blog.stevensanderson.com/2010/01/28/editing-a-variable-length-list-aspnet-mvc-2-style/

Nuget Package: http://www.nuget.org/packages/BeginCollectionItem/

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文