2012-09-10 11 views
8

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

विभिन्न फ़ील्ड दिखाने की विधि प्राप्त करने के लिए मैं एक HTMLHelper एक्सटेंशन बनाने का प्रयास कर रहा हूं जो पैरामीटर के रूप में Expression<Func<TModel,TProperty>> स्वीकार करता है, जिसमें नियंत्रण में प्रदर्शन के लिए आवश्यक कक्षा के गुण शामिल होंगे। उदाहरण के लिए:

दृश्य:

@model Project.Core.Page 
@Html.MyHelper(p => new { p.Author.Name, p.Author.Location, p.Author.Age }); 

यह विस्तार मैं साथ में समस्या आ रही है - मैं कैसे लैम्ब्डा भी एक TextBoxFor() के साथ प्रत्येक प्रदान करने के लिए, या में प्रदान की पैरामीटर से अधिक पुनरावृति कर सकते हैं मैन्युअल रूप से एक बनाने के input तत्व और lambda पैरामीटर के value और name के साथ इसे पॉप्युलेट करें?

छद्म में विस्तार:

public static MvcHtmlString MyHelper<TModel,TProperty>(
    this HtmlHelper<TModel> helper, 
    Expression<Func<TModel,TProperty>> expression) { 
    foreach (var parameter in expression.???) { 
     // helper.TextBoxFor(???) 
     // TagBuilder("input").Attributes("name", expression.???) 
    } 
} 

मुझे लगता है कि मैं अभी तक बहुत लंबे समय के लिए इस घूर कर रहा है, और मैं भी वहाँ एक और अधिक आसान तरीका मैं इस को प्राप्त करने का अनदेखी हूँ महसूस कर रहा हूँ।

किसी भी मदद की बहुत सराहना की जाती है। अगर आपको और जानकारी चाहिए, या मुझे कुछ महत्वपूर्ण याद आया है, तो मुझे बताएं।

+0

प्रश्न और मेरी प्रतिक्रिया को दोबारा पढ़ने के बाद, मुझे एहसास हुआ कि मेरा पहला उदाहरण मॉडल पर जटिल गुणों के मूल्यों को एक्सेस नहीं कर सका। मैंने इस स्थिति के लिए अपने कोड उदाहरण को अपडेट किया है। – mclark1129

उत्तर

2

, तो आप निम्न मान:

  1. इनपुट अभिव्यक्ति का परिणाम एक प्रक्षेपण (रिटर्न एक नई वस्तु, गुमनाम या अन्यथा)
  2. तत्वों है प्रक्षेपण के सभी MemberExpressions हैं, और मॉडल या उसके बच्चों पर एक विधि में कॉल नहीं है

तो फिर तुम हासिल कर सकते हैं निम्नलिखित दृष्टिकोण का उपयोग करके आप क्या चाहते हैं:

संपादित करें:

एहसास है कि मेरा पहला उदाहरण जटिल गुणों के साथ वस्तुओं नहीं संभाल सकता के बाद, मैं एक सहायक का उपयोग करने के कोड अद्यतन संपत्ति मूल्यों तक पहुंचने के लिए विधि। यह विधि उपयुक्त मूल्यों को वापस करने के लिए रिकर्सन का उपयोग करके संपत्ति श्रृंखला पर जाती है।

public static MvcHtmlString MyHelper<TModel,object>(
    this HtmlHelper<TModel> helper, 
    Expression<Func<TModel,object>> expression) { 

     var newExpression = expression.Body as NewExpression; 
     TModel model = helper.ViewData.Model; 

     foreach (MemberExpression a in newExpression.Arguments) { 

      var propertyName = a.Member.Name; 
      var propertyValue = GetPropertyValue<TModel>(model, a); 

      // Do whatever you need to with the property name and value; 

     } 

    } 

    private static object GetPropertyValue<T>(T instance, MemberExpression me) { 

     object target; 

     if (me.Expression.NodeType == ExpressionType.Parameter) { 
      // If the current MemberExpression is at the root object, set that as the target.    
      target = instance; 
     } 
     else {     
      target = GetPropertyValue<T>(instance, me.Expression as MemberExpression); 
     } 

     // Return the value from current MemberExpression against the current target 
     return target.GetType().GetProperty(me.Member.Name).GetValue(target, null); 

    } 

नोट: मैं अपने आईडीई में एक MVC विस्तार विधि, इसलिए वाक्य रचना की एक मामूली बदलाव आवश्यक हो सकता है के रूप में सीधे यह लागू नहीं किया।

2

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

यदि आप कोड को बुलाने की एक से थोड़ा भद्दा फार्म के लिए व्यवस्थित करने के लिए खुशी होगी, यह ज्यादा सरल लागू करने के लिए इस होगा:

@Html.MyHelper(p => p.Author.Name, p => p.Author.Location, p => p.Author.Age); 

आप कर सकता है कि लेने के एक params Expression<TModel, object> या आप यह घोषणा कर सकता है पैरामीटर की विभिन्न संख्याओं के साथ एकाधिक अधिभार, उदाहरण के लिए

// Overload for one property 
MyHelper<TModel, TProperty1>(this ..., Expression<Func<TModel, TProperty1>> func1) 

// Overload for two properties 
MyHelper<TModel, TProperty1, TProperty2>(this ..., 
    Expression<Func<TModel, TProperty1>> func1, 
    Expression<Func<TModel, TProperty2>> func2) 

आदि

+0

मैंने इस दृष्टिकोण को माना था, लेकिन जैसा कि आप कहते हैं कि यह थोड़ा अस्पष्ट है, मैं इसे 'प्लान बी' के रूप में रखूंगा। :) जवाब देने के लिए धन्यवाद, जॉन। –

1

शायद एक बिल्डर शैली API चीजों को आसान बनाने में कर सकता है:

@(Html.MyHelper(p) 
    .Add(p => p.Author.Age) 
    .Add(p => p.Author.LastName, "Last Name") 
    .Build()) 

सूचना है कि इस मामले में आप वैकल्पिक पैरामीटर जोड़ने के लिए आप उन्हें जरूरत अनुमति देता है।

कोड इस

public static class Test 
{ 
    public static Helper<TModel> MyHelper<TModel>(this HtmlHelper helper, TModel model) 
    { 
     return new Helper<TModel>(helper, model); 
    } 
} 

public class Helper<TModel> 
{ 
    private readonly HtmlHelper helper; 
    private readonly TModel model; 

    public Helper(HtmlHelper helper, TModel model) 
    { 
     this.helper = helper; 
     this.model = model; 
    } 

    public Helper<TModel> Add<TProperty>(Expression<Func<TModel, TProperty>> expression) 
    { 
     // TODO 
     return this; 
    } 

    public MvcHtmlString Build() 
    { 
     return new MvcHtmlString("TODO"); 
    } 
} 
1

कुछ ऐसा दिखाई देगा इस पर विचार करें:

App_Code फ़ोल्डर

बनाएं उस्तरा सहायक फ़ाइल Templates.cshtml रखो।

@helper Print(string myvalue,string special="") 
{ 
    <pre> <input id="id" type="text" value ="@myvalue" data-val="@special"/> </pre> 
} 

इस तरह से आप न सी # फ़ाइलों में HTML लिखने के लिए है:

यह नीचे की तरह दिखता है। यह बहुत आसान है।

Authors.cshtml नीचे दिखाई देता है:

@model IEnumerable<MvcApplication1.Models.Author> 
@{ 
    ViewBag.Title = "Authors"; 
} 

<h2>Authors</h2> 

@foreach(var auth in Model) 
{ 
    @Templates.Print(auth.Name);  
} 

books.cshtml नीचे दिखाई देता है:

@model IEnumerable<MvcApplication1.Models.Book> 
@{ 
    ViewBag.Title = "Books"; 
} 

<h2>Books</h2> 

@foreach(var book in Model) 
{ 
    @Templates.Print(book.Title,book.ISBN);  
} 

सभी विशेष गुण प्लगइन के रूप में आप मॉडल प्रति कक्षा की जरूरत है। यदि यह बहुत जटिल हो जाता है, तो गतिशील और विस्तारित ऑब्जेक्ट में देखें। यह इस बात पर निर्भर करता है कि आपके मॉडल/व्यूमोडेल कितने जटिल हैं।

संबंधित मुद्दे