त्वरित उत्तर for()
आपके foreach()
छोरों के स्थान पर एक लूप का उपयोग करना है। कुछ इस तरह:
@for(var themeIndex = 0; themeIndex < Model.Theme.Count(); themeIndex++)
{
@Html.LabelFor(model => model.Theme[themeIndex])
@for(var productIndex=0; productIndex < Model.Theme[themeIndex].Products.Count(); productIndex++)
{
@Html.LabelFor(model=>model.Theme[themeIndex].Products[productIndex].name)
@for(var orderIndex=0; orderIndex < Model.Theme[themeIndex].Products[productIndex].Orders; orderIndex++)
{
@Html.TextBoxFor(model => model.Theme[themeIndex].Products[productIndex].Orders[orderIndex].Quantity)
@Html.TextAreaFor(model => model.Theme[themeIndex].Products[productIndex].Orders[orderIndex].Note)
@Html.EditorFor(model => model.Theme[themeIndex].Products[productIndex].Orders[orderIndex].DateRequestedDeliveryFor)
}
}
}
लेकिन यह इस समस्या को ठीक क्यों करता है, इस पर ग्लॉज़ होता है।
तीन चीजें हैं जो आपके पास कम से कम एक सरसरी समझ है इससे पहले कि आप इस मुद्दे को हल कर सकें। मुझे यह स्वीकार करना होगा कि मैंने लंबे समय तक कार्गो की खेती की जब मैंने फ्रेमवर्क के साथ काम करना शुरू किया। और मुझे वास्तव में जो कुछ हो रहा था उसे पाने में काफी समय लगा।
वे तीन चीजें हैं:
- MVC में
LabelFor
अन्य ...For
सहायक कैसे काम करते हैं?
- एक्सप्रेशन ट्री क्या है?
- मॉडल बाइंडर कैसे काम करता है?
इन तीनों अवधारणाओं का उत्तर पाने के लिए एक साथ लिंक करें।
MVC में LabelFor
अन्य ...For
सहायक कैसे काम करते हैं?
इसलिए, जब आप का उपयोग किया है HtmlHelper<T>
के लिए एक्सटेंशन LabelFor
और TextBoxFor
और अन्य लोगों, और आप शायद गौर किया है कि जब आप उन्हें आह्वान, तो आप उन्हें एक लैम्ब्डा गुजरती हैं और यह जादुई कुछ html उत्पन्न करता है। पर कैसे?
तो पहली बात नोटिस इन सहायकों के लिए हस्ताक्षर है। के लिए सबसे सरल अधिभार को देखने की सुविधा देता है
TextBoxFor
public static MvcHtmlString TextBoxFor<TModel, TProperty>(
this HtmlHelper<TModel> htmlHelper,
Expression<Func<TModel, TProperty>> expression
)
सबसे पहले, यह एक HtmlHelper
प्रकार का जोरदार टाइप के लिए एक विस्तार विधि है <TModel>
। इसलिए, केवल यह बताने के लिए कि पर्दे के पीछे क्या होता है, जब रेजर इस दृश्य को प्रस्तुत करता है तो यह एक वर्ग उत्पन्न करता है। इस वर्ग के अंदर एक उदाहरण है HtmlHelper<TModel>
(संपत्ति के रूप में Html
, जिसके कारण आप इसका उपयोग कर सकते हैं @Html...
), TModel
आपके @model
कथन में परिभाषित प्रकार कहां है । तो आपके मामले में, जब आप इस दृश्य TModel
को देख रहे हैं तो यह हमेशा प्रकार का होगा ViewModels.MyViewModels.Theme
।
अब, अगला तर्क थोड़ा मुश्किल है। तो चलो एक आह्वान को देखो
@Html.TextBoxFor(model=>model.SomeProperty);
ऐसा लगता है कि हमारे पास थोड़ा सा लंबोदा है, और अगर किसी को हस्ताक्षर का अनुमान लगाना था, तो कोई सोच सकता है कि इस तर्क के लिए प्रकार केवल एक होगा Func<TModel, TProperty>
, जहां TModel
दृश्य मॉडल TProperty
का प्रकार है और संपत्ति के प्रकार के रूप में अनुमान लगाया गया है।
लेकिन यह बिल्कुल सही नहीं है, अगर आप तर्क के वास्तविक प्रकार को देखें Expression<Func<TModel, TProperty>>
।
इसलिए जब आप सामान्य रूप से एक लैम्ब्डा उत्पन्न करते हैं, तो कंपाइलर लैम्ब्डा लेता है और इसे MSIL में संकलित करता है, किसी अन्य फ़ंक्शन की तरह (जिसके कारण आप डेलिगेट्स, मेथड ग्रुप, और लैम्ब्डा का कम या ज्यादा इंटरचेंज का उपयोग कर सकते हैं, क्योंकि वे सिर्फ कोड रेफरेंस हैं। ।)
हालांकि, जब कंपाइलर देखता है कि प्रकार एक है Expression<>
, तो यह तुरंत लैम्बडा को एमएसआईएल के लिए संकलित नहीं करता है, इसके बजाय यह एक अभिव्यक्ति ट्री उत्पन्न करता है!
तो, क्या बिल्ली एक अभिव्यक्ति पेड़ है। ठीक है, यह जटिल नहीं है, लेकिन पार्क में चलना भी नहीं है। एमएस को उद्धृत करने के लिए:
| अभिव्यक्ति के पेड़ एक पेड़ की तरह डेटा संरचना में कोड का प्रतिनिधित्व करते हैं, जहां प्रत्येक नोड एक अभिव्यक्ति है, उदाहरण के लिए, एक विधि कॉल या बाइनरी ऑपरेशन जैसे x <y।
सीधे शब्दों में कहें, एक अभिव्यक्ति पेड़ "कार्यों" के संग्रह के रूप में एक समारोह का प्रतिनिधित्व है।
के मामले में model=>model.SomeProperty
, अभिव्यक्ति के पेड़ में एक नोड होता है जो कहता है: "एक मॉडल से" कुछ संपत्ति प्राप्त करें "
इस अभिव्यक्ति के पेड़ को एक फ़ंक्शन में संकलित किया जा सकता है, लेकिन जब तक यह एक अभिव्यक्ति पेड़ है, तब तक यह सिर्फ नोड्स का संग्रह है।
तो इसके लिए क्या अच्छा है?
तो Func<>
या Action<>
, एक बार जब आप उन्हें है, वे बहुत ज्यादा परमाणु हैं। आप वास्तव में Invoke()
उन्हें कर सकते हैं, उर्फ उन्हें वह काम करने को कहें जो वे करने वाले हैं।
Expression<Func<>>
दूसरी ओर, क्रियाओं के एक संग्रह का प्रतिनिधित्व करता है, जिसे जोड़ा जा सकता है, हेरफेर किया जा सकता है, दौरा किया जा सकता है , या संकलित और लागू किया जा सकता है।
तो आप मुझे यह सब क्यों बता रहे हैं?
तो क्या है की समझ के साथ Expression<>
, हम वापस जा सकते हैं Html.TextBoxFor
। जब यह एक टेक्स्टबॉक्स प्रस्तुत करता है, तो आपको उस संपत्ति के बारे में कुछ चीजें उत्पन्न करने की आवश्यकता होती है जो आप दे रहे हैं। attributes
सत्यापन के लिए संपत्ति पर चीजें पसंद हैं, और विशेष रूप से इस मामले में यह पता लगाने की आवश्यकता है कि टैग का नाम क्या है <input>
।
यह अभिव्यक्ति पेड़ का "चलना" और एक नाम का निर्माण करता है। तो जैसे एक अभिव्यक्ति के लिए model=>model.SomeProperty
, यह उस गुण को इकट्ठा करता है जो आप के लिए पूछ रहे हैं और बनाता है <input name='SomeProperty'>
।
अधिक जटिल उदाहरण के लिए, जैसे model=>model.Foo.Bar.Baz.FooBar
, यह उत्पन्न हो सकता है<input name="Foo.Bar.Baz.FooBar" value="[whatever FooBar is]" />
सही बात? यह केवल वह कार्य नहीं है जो Func<>
करता है, लेकिन यह अपना कार्य कैसे करता है यह यहां महत्वपूर्ण है।
(ध्यान दें कि LINQ से SQL जैसी अन्य चौखटें एक अभिव्यक्ति पेड़ पर चलने और एक अलग व्याकरण का निर्माण करके इसी तरह की चीजें करती हैं, ताकि यह SQL क्वेरी हो)
मॉडल बाइंडर कैसे काम करता है?
तो एक बार जब आप ऐसा कर लेते हैं, तो हमें मॉडल बाइंडर के बारे में संक्षेप में बात करनी होगी। जब फॉर्म पोस्ट हो जाता है, तो यह एक फ्लैट की तरह होता है
Dictionary<string, string>
, हमने अपने नेस्टेड व्यू मॉडल को पदानुक्रमित संरचना खो दिया है। यह इस महत्वपूर्ण-मूल्य जोड़ी कॉम्बो को लेने के लिए मॉडल बाइंडर का काम है और कुछ गुणों के साथ किसी ऑब्जेक्ट को फिर से व्यवस्थित करने का प्रयास करता है। यह ऐसे कैसे करता है? आपने अनुमान लगाया, "कुंजी" या इनपुट के नाम का उपयोग करके जो पोस्ट किया गया है।
तो अगर फॉर्म पोस्ट दिखता है
Foo.Bar.Baz.FooBar = Hello
और आप नामक एक मॉडल को पोस्ट कर रहे हैं SomeViewModel
, फिर यह रिवर्स करता है कि सहायक ने पहले स्थान पर क्या किया था। यह "फू" नामक एक संपत्ति की तलाश करता है। फिर यह "फू" से "बार" नामक एक संपत्ति की तलाश करता है, फिर यह "बाज" के लिए दिखता है ... और इसी तरह ...
अंत में यह "फूबर" के प्रकार में मूल्य को पार्स करने की कोशिश करता है और इसे "फूबर" को सौंपता है।
ओफ़्फ़ !!!
और वोइला, आपके पास अपना मॉडल है। मॉडल बाइंडर का अभी-अभी बनाया गया उदाहरण अनुरोधित कार्रवाई में सौंप दिया गया है।
इसलिए आपका समाधान काम नहीं करता है क्योंकि Html.[Type]For()
सहायकों को एक अभिव्यक्ति की आवश्यकता होती है। और आप उन्हें सिर्फ एक मूल्य दे रहे हैं। यह पता नहीं है कि उस मूल्य के लिए संदर्भ क्या है, और यह नहीं जानता कि इसके साथ क्या करना है।
अब कुछ लोगों ने रेंडर करने के लिए partials का उपयोग करने का सुझाव दिया। अब यह सिद्धांत रूप में काम करेगा, लेकिन शायद वह तरीका नहीं है जिसकी आप अपेक्षा करते हैं। जब आप एक आंशिक रेंडर करते हैं, तो आप का प्रकार बदल रहे हैं TModel
, क्योंकि आप एक अलग दृश्य संदर्भ में हैं। इसका मतलब है कि आप अपनी संपत्ति का वर्णन कम अभिव्यक्ति के साथ कर सकते हैं। इसका अर्थ यह भी है कि जब सहायक आपकी अभिव्यक्ति के लिए नाम बनाता है, तो यह उथला होगा। यह केवल उसके द्वारा दी गई अभिव्यक्ति (संपूर्ण संदर्भ नहीं) के आधार पर उत्पन्न होगा।
तो चलिए आपको बताते हैं कि आपने "बाज" (पहले हमारे उदाहरण से) प्रदान किया था। उस आंशिक के अंदर आप बस कह सकते हैं:
@Html.TextBoxFor(model=>model.FooBar)
बजाय
@Html.TextBoxFor(model=>model.Foo.Bar.Baz.FooBar)
इसका मतलब है कि यह इस तरह एक इनपुट टैग उत्पन्न करेगा:
<input name="FooBar" />
जो, यदि आप इस फॉर्म को एक ऐसे एक्शन में पोस्ट कर रहे हैं, जो एक बड़े नेस्टेड व्यूमॉडल की उम्मीद कर रहा है, तो यह एक प्रॉपर्टी को FooBar
ऑफ- हाइड करने की कोशिश करेगा TModel
। जो सबसे अच्छा नहीं है, और सबसे बुरी तरह से पूरी तरह से कुछ और है। यदि आप एक विशिष्ट क्रिया को पोस्ट कर रहे थे Baz
जो रूट मॉडल के बजाय एक को स्वीकार कर रहा था , तो यह बहुत अच्छा काम करेगा! वास्तव में, आपके विचार के संदर्भ को बदलने के लिए पार्टिकल्स एक अच्छा तरीका है, उदाहरण के लिए यदि आपके पास कई रूपों के साथ एक पृष्ठ है जो सभी विभिन्न कार्यों के लिए पोस्ट करते हैं, तो प्रत्येक के लिए एक आंशिक प्रतिपादन एक महान विचार होगा।
अब एक बार जब आप इस सब को प्राप्त कर लेते हैं, तो आप वास्तव में दिलचस्प चीजों के साथ शुरू कर सकते हैं Expression<>
, कार्यक्रम को बढ़ाकर और उनके साथ अन्य स्वच्छ चीजें कर सकते हैं। मैं उस में से किसी में नहीं मिलेगा। लेकिन, उम्मीद है, यह आपको पर्दे के पीछे क्या चल रहा है और क्यों चीजें जिस तरह से काम कर रही हैं, उससे बेहतर समझ मिलेगी।
@
सब से पहले नहीं होना चाहिएforeach
? क्या आपकोHtml.EditorFor
(Html.EditorFor(m => m.Note)
उदाहरण के लिए) और बाकी तरीकों में भी लंबोदा नहीं होना चाहिए ? मैं गलत हो सकता हूं, लेकिन क्या आप अपना वास्तविक कोड पेस्ट कर सकते हैं? मैं एमवीसी के लिए बहुत नया हूं, लेकिन आप इसे आंशिक विचारों, या संपादकों (यदि यह नाम है) के साथ आसानी से हल कर सकते हैं।