2011-12-22 7 views
37

क्या यह सच है कि एमवीसी 3.0 में डिफ़ॉल्ट मॉडल बाइंडर गैर अनुक्रमिक सूचकांक (सरल और जटिल मॉडल प्रकार दोनों के लिए) को संभालने में सक्षम है? मैं उन पदों पर आया हूं जो सुझाव देते हैं कि यह चाहिए, हालांकि मेरे परीक्षणों में ऐसा प्रतीत होता है कि यह नहीं है।एमवीसी 3 गैर-अनुक्रमिक सूचकांक और डिफ़ॉल्ट मॉडेलबिन्डर

को देखते हुए पद वापस मान:

items[0].Id = 10 
items[0].Name = "Some Item" 
items[1].Id = 3 
items[1].Name = "Some Item" 
items[4].Id = 6 
items[4].Name = "Some Item" 

और एक नियंत्रक विधि:

public ActionResult(IList<MyItem> items) { ... } 

केवल मानों भरी हुई हैं 0 आइटम और 1 हैं; आइटम 4 को अनदेखा किया जाता है।

मैंने कस्टम इंडेक्स (Model Binding to a List) उत्पन्न करने के लिए कई समाधान देखे हैं, हालांकि वे सभी एमवीसी के पिछले संस्करणों को लक्षित करने के लिए दिखाई देते हैं, और अधिकांश कुछ 'भारी हाथ' आईएमओ हैं।

मैं कुछ याद आ रही है?

उत्तर

63

मैं इस काम के है, तो आप के रूप में अपने संदर्भित लेख में बताया गया है एक आम अनुक्रमण छिपे हुए इनपुट को जोड़ने के लिए याद करने के लिए है:

name = Items.Index साथ छिपे हुए इनपुट महत्वपूर्ण हिस्सा

<input type="hidden" name="Items.Index" value="0" /> 
<input type="text" name="Items[0].Name" value="someValue1" /> 

<input type="hidden" name="Items.Index" value="1" /> 
<input type="text" name="Items[1].Name" value="someValue2" /> 

<input type="hidden" name="Items.Index" value="3" /> 
<input type="text" name="Items[3].Name" value="someValue3" /> 

<input type="hidden" name="Items.Index" value="4" /> 
<input type="text" name="Items[4].Name" value="someValue4" /> 

आशा है कि यह मदद करता है

+0

मैं से बचने के लिए उम्मीद कर रही थी यह दृष्टिकोण। मैंने अपनी उंगलियों को पार किया था कि डिफ़ॉल्ट मॉडल बांधने वाला व्यक्ति लापता इंडिस को ही हल करेगा। इंडेक्स को स्पष्ट रूप से निर्दिष्ट करने के लिए एक कारण होना चाहिए (शायद अधिक जटिल स्थितियों के लिए?)। किसी भी तरह से, त्वरित उत्तर और नमूना कोड के लिए धन्यवाद। – mindlessgoods

+1

धन्यवाद, पूरी तरह से काम करता है! – Levitikon

+4

ओएच मेरा एनयूएल! यह सिर्फ लौटने वाली सूचियों को इतना आसान बनाता है, (i ++) के लिए हास्यास्पद करने के बजाय मैं केवल प्राथमिक कुंजी या इंडेक्स पर किसी अन्य आईडी का उपयोग कर सकता हूं, और सूची वापस इतनी अच्छी और दृढ़ता से टाइप की जाती है। ये अंधेरे, छिपा रहस्य। इससे आज मेरा काम बन गया! +1 + बियर !!! – ppumkin

4

आपके द्वारा संदर्भित आलेख एक पुराना (एमवीसी 2) है, लेकिन जहां तक ​​मुझे पता है, यह अभी भी डिफॉल्ट मॉडलबिंडर का उपयोग करके बाध्य संग्रह मॉडल करने का डिफैक्टो तरीका है।

यदि आप गैर अनुक्रमिक अनुक्रमण चाहते हैं, जैसे बासम कहते हैं, तो आपको एक सूचकांक निर्दिष्ट करने की आवश्यकता होगी। सूचकांक को संख्यात्मक होने की आवश्यकता नहीं है।

हम इसके लिए Steve Sanderson's BeginCollectionItem Html Helper का उपयोग करते हैं। यह स्वचालित रूप से सूचकांक को ग्रिड के रूप में उत्पन्न करता है। मुझे लगता है कि यह आपके कंटेंट आइटम एचटीएमएल गैर अनुक्रमिक होने पर संख्यात्मक सूचकांक का उपयोग करने से बेहतर तरीका है।

+0

मैं उसी लेख में आया, और यह निश्चित रूप से उस मुद्दे को संबोधित करता था जिसका मैं वर्णन कर रहा था। जैसा कि ऊपर बताया गया है, मैं उम्मीद कर रहा था कि डिफ़ॉल्ट मॉडल बाइंडर आंतरिक रूप से इस स्थिति को संभालेगा और शुरुआतकोलेक्शनइटम हेल्पर की वास्तव में आवश्यकता नहीं थी। उत्तर के लिए धन्यवाद! – mindlessgoods

5

स्टीव सैंडर्सन के दृष्टिकोण से प्राप्त यह सहायक विधि बहुत आसान है और संग्रह में किसी भी आइटम को एंकर करने के लिए इसका उपयोग किया जा सकता है और ऐसा लगता है कि यह एमवीसी मॉडल बाध्यकारी के साथ काम करता है।

public static IHtmlString AnchorIndex(this HtmlHelper html) 
{ 
    var htmlFieldPrefix = html.ViewData.TemplateInfo.HtmlFieldPrefix; 
    var m = Regex.Match(htmlFieldPrefix, @"([\w]+)\[([\w]*)\]"); 
    if (m.Success && m.Groups.Count == 3) 
     return 
      MvcHtmlString.Create(
       string.Format(
        "<input type=\"hidden\" name=\"{0}.index\" autocomplete=\"off\" value=\"{1}\" />", 
        m.Groups[1].Value, m.Groups[2].Value)); 
    return null; 
} 

उदा। बस इसे एक संपादक टेम्पलेट में कॉल करें, या कहीं भी आप इनपुट जेनरेट करेंगे, जैसा कि कोई लागू होता है, इंडेक्स एंकरिंग छुपा चर उत्पन्न करने के लिए।

@model SomeViewModel 
@Html.AnchorIndex() 
@Html.TextBoxFor(m => m.Name) 
... etc. 

मुझे लगता है कि स्टीव सैंडरसन के दृष्टिकोण से अधिक कुछ फायदे हैं।

  1. यह घटक के लिए काम करता है और अन्य इनबिल्ट तंत्रों को संसाधित करने के लिए काम करता है। तो अगर Items एक दृश्य के मॉडल पर एक IEnumerable<T> संपत्ति है, उम्मीद के रूप में निम्नलिखित काम करता है:

    <ul id="editorRows" class="list-unstyled"> @Html.EditorFor(m => m.Items) @* Each item will correctly anchor allowing for dynamic add/deletion via Javascript *@ </ul>

  2. यह आसान है और किसी भी अधिक जादू तार की आवश्यकता नहीं है।

  3. आप एक डेटा प्रकार के लिए हो सकता है एक भी EditorTemplate/DisplayTemplate और यह बस कोई को-अप करता है, तो एक सूची में किसी आइटम पर इस्तेमाल नहीं किया जाएगा।

केवल नकारात्मक पक्ष यह है कि अगर जड़ मॉडल बाध्य किया जा रहा (कार्रवाई विधि ही है और नहीं बस एक कहीं गहरी पैरामीटर वस्तु ग्राफ में संपत्ति के लिए पैरामीटर यानी), बंधन में असफल हो जायेगी गणनीय है पहली गैर अनुक्रमिक सूचकांक। दुर्भाग्यवश, DefaultModelBinder की .Index कार्यक्षमता केवल गैर-रूट ऑब्जेक्ट्स के लिए काम करती है। इस परिदृश्य में, आपका एकमात्र विकल्प उपर्युक्त दृष्टिकोणों का उपयोग करना बाकी है।

+0

इस फिल के लिए बहुत धन्यवाद। मैं एनामेरबल्स के साथ EditorFor का उपयोग करने के लिए काफी प्रतिबद्ध हूं और यह एक आकर्षण की तरह काम करता है! – Jono

1

या इस जावास्क्रिप्ट समारोह का उपयोग अनुक्रमण ठीक करने के लिए: (EntityName और FieldName स्पष्ट रूप से बदलें)

function fixIndexing() { 
     var tableRows = $('#tblMyEntities tbody tr'); 

     for (x = 0; x < tableRows.length; x++) { 
      tableRows.eq(x).attr('data-index', x); 

      tableRows.eq(x).children('td:nth-child(1)').children('input:first').attr('name', 'EntityName[' + x + "].FieldName1"); 

      tableRows.eq(x).children('td:nth-child(2)').children('input:first').attr('name', 'EntityName[' + x + "].FieldName2"); 

      tableRows.eq(x).children('td:nth-child(3)').children('input:first').attr('name', 'EntityName[' + x + "].FieldName3"); 
     } 

     return true; //- Submit Form - 
    } 
2

मैं इस सप्ताह इस के साथ संघर्ष कर रहा था और बास्साम के जवाब सही रास्ते पर मुझे प्राप्त करने के लिए महत्वपूर्ण था। मेरे पास इन्वेंट्री आइटम की गतिशील सूची है जिसमें मात्रा फ़ील्ड हो सकती है। मुझे यह जानने की जरूरत है कि आइटमों की सूची को छोड़कर, उनमें से कितने आइटम चुने गए हैं, 1 से एन से भिन्न हो सकते हैं।

मेरे समाधान अंत में बल्कि एक सरल था। मैंने दो गुणों के साथ ItemVM नामक एक व्यूमोडेल बनाया। आइटम आईडी और मात्रा। पोस्ट एक्शन में मैं इनमें से एक सूची स्वीकार करता हूं। इंडेक्सिंग के साथ, सभी आइटम पास हो जाते हैं .. यहां तक ​​कि शून्य मात्रा के साथ भी। आपको सर्वर पक्ष को सत्यापित और संभालना होगा, लेकिन पुनरावृत्ति के साथ इस गतिशील सूची को संभालने के लिए यह छोटा है। कुछ इस तरह

मेरे विचार में मैं उपयोग कर रहा हूँ:

@foreach (Item item in Items) 
{ 
<input type="hidden" name="OrderItems.Index" value="@item.ItemID" /> 
<input type="hidden" name="OrderItems[@item.ItemID].ItemID" value="@item.ItemID" /> 
<input type="number" name="OrderItems[@item.ItemID].Quantity" /> 
} 

यह मैं एक 0-आधारित सूचकांक के साथ एक सूची देता है, लेकिन नियंत्रक में यात्रा एक नया जोरदार टाइप मॉडल से सभी आवश्यक डेटा निकालता है ।

public ActionResult Marketing(List<ItemVM> OrderItems) 
... 
     foreach (ItemVM itemVM in OrderItems) 
      { 
       OrderItem item = new OrderItem(); 
       item.ItemID = Convert.ToInt16(itemVM.ItemID); 
       item.Quantity = Convert.ToInt16(itemVM.Quantity); 
       if (item.Quantity > 0) 
       { 
        order.Items.Add(item); 
       } 
      } 

फिर आप उन वस्तुओं के संग्रह के साथ समाप्त हो जाएंगे जिनमें 0 से अधिक मात्रा और आइटम आईडी है।

इस तकनीक MVC 5 में काम कर रहा है दृश्य स्टूडियो 2015 में एफई 6 का उपयोग हो सकता है कि यह इस समाधान के लिए खोज की तरह मैं था किसी को मदद मिलेगी।

+0

क्या आप पूरा उदाहरण प्रदान कर सकते हैं? मेरे पास बहुत ही समान स्थिति है –

1

मैं एक अधिक सामान्य एचटीएमएल हेल्पर बनाने समाप्त हो गया: -

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Linq.Expressions; 
using System.Text; 
using System.Text.RegularExpressions; 
using System.Web; 
using System.Web.Mvc; 

namespace Wallboards.Web.Helpers 
{ 
    /// <summary> 
    /// Hidden Index Html Helper 
    /// </summary> 
    public static class HiddenIndexHtmlHelper 
    { 
     /// <summary> 
     /// Hiddens the index for. 
     /// </summary> 
     /// <typeparam name="TModel">The type of the model.</typeparam> 
     /// <typeparam name="TProperty">The type of the property.</typeparam> 
     /// <param name="htmlHelper">The HTML helper.</param> 
     /// <param name="expression">The expression.</param> 
     /// <param name="index">The Index</param> 
     /// <returns>Returns Hidden Index For</returns> 
     public static MvcHtmlString HiddenIndexFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, int index) 
     { 
      var metadata = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData); 
      var propName = metadata.PropertyName; 

      StringBuilder sb = new StringBuilder(); 
      sb.AppendFormat("<input type=\"hidden\" name=\"{0}.Index\" autocomplete=\"off\" value=\"{1}\" />", propName, index); 

      return MvcHtmlString.Create(sb.ToString()); 
     } 
    } 
} 

और फिर अपने उस्तरा दृश्य में सूची तत्व के प्रत्येक चरण में यह शामिल हैं: -

@Html.HiddenIndexFor(m => m.ExistingWallboardMessages, i)