2011-04-18 43 views
5

我從以下菲爾哈克模型綁定到MVC 3中可能存在非順序索引的列表?

http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx的信息他談到非序列指標:

<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結合這可能嗎?
這是sequentiel指數來做到這一點:

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

如果這是不可能的,是他們的任何東西,如果我的索引將不會是連續的,我可以做什麼?

+0

這仍然是項目的順序列表。除了生成替代索引HTML之外,您需要提供更多的上下文以瞭解您要實現的目標。你是否試圖實現收集項目重新排序,添加和刪除,否則你不需要這種語法? – 2011-06-04 19:47:50

回答

1

AFAI瞭解非順序索引技術需要爲每個索引值添加隱藏字段。我很確定Html.TextBoxFor幫手本身不會產生任何額外的隱藏字段。可能你可以通過手動添加帶有非序列索引的隱藏字段來實現這一點。

0

我試過這個,我無法讓它與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隱藏索引。

讓我知道如果這不起作用我有一個這樣做的方式,我只是從我的頭頂採取這一點。

+0

我試圖得到這個工作,因爲你提到,而不必使用隱藏的輸入的索引,我不能完全得到它的工作。你有沒有工作的例子? – 2011-08-22 17:05:07

0

爲了不擾亂你的觀點,我發現要做到這一點的最簡單方法是遵循這個擴展: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> 

我覺得這比你在視圖中的索引更乾淨... 這裏是解釋如何做到一步一步的帖子EP:http://blog.stevensanderson.com/2010/01/28/editing-a-variable-length-list-aspnet-mvc-2-style/

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