2012-04-04 11 views
6

मैं एक फ़िल्टर संपत्ति के साथ एक ViewModel है के लिए गुणों के साथ एक ActionLink बनाने के लिए कैसे:कई गुण है कि मैं अपने डेटा को फ़िल्टर करने</p> <p>उदाहरण का उपयोग किया है कि देखें मॉडल

class MyViewModel : IHasFilter 
{ 
    public MyData[] Data { get; set; } 
    public FilterViewModel Filter { get; set; } 
} 

class FilterViewModel 
{ 
    public String MessageFilter { get; set; } 
    //etc. 
} 

यह ठीक काम करता है जब मेरे दृश्य का उपयोग कर। मैं Model.Filter के गुण सेट कर सकता हूं और वे नियंत्रक को पास कर दिए जाते हैं। मैं अब क्या करने की कोशिश कर रहा हूं, ActionLink बनाएं जिसमें एक क्वेरी स्ट्रिंग है जो उपरोक्त प्रारूप के साथ काम करती है।

क्वेरी ऊपर से मेरी दृश्य द्वारा उत्पन्न स्ट्रिंग इस तरह दिखता है:

http://localhost:51050/?Filter.MessageFilter=Stuff&Filter.OtherProp=MoreStuff 

मैं एक ग्रिड है कि इसके बाद के संस्करण देखें को जाता है में प्रत्येक पंक्ति के लिए एक अलग दृश्य में एक ActionLink उत्पन्न करने के लिए की जरूरत है।

मैं कोशिश की है:

new MyViewModel { Filter = new FilterViewModel { MessageFilter = item.Message, }, }, 

लेकिन इन उपरोक्त के समान क्वेरी स्ट्रिंग उत्पन्न नहीं है:

Html.ActionLink(
    item.Message, 
    "Index", 
    "Home", 
    new { Filter = new { MessageFilter = item.Message, }, }, 
    null); 

मैं भी करने के लिए routeValues तर्क स्थापित करने की कोशिश की।

+0

+1 एक अच्छा सवाल –

+0

संपादन के लिए धन्यवाद; मैंने जवाब का दोबारा जवाब दिया और प्रतिस्थापन में 'उपसर्ग' को जोड़ना भूल गया! –

+0

@AndrasZoltan कोई समस्या नहीं है। – DaveShaw

उत्तर

1

आप एक FilterViewModel उदाहरण से एक RouteValueDictionary बना सकते हैं और फिर उस पर ToDictionary का उपयोग सभी कुंजियों 'Filter.' साथ उपसर्ग के साथ एक और RouteValues ​​को पारित करने के लिए।

यह आगे ले जाने पर आप जो एक उपसर्ग स्वीकार करता RouteValueDictionary की एक विशेष ओवरराइड का निर्माण कर सकता है (इसलिए इसे और अधिक अन्य परिदृश्यों के लिए उपयोगी बनाता): इसी के साथ

public class PrefixedRouteValueDictionary : RouteValueDictionary 
{ 
    public PrefixedRouteValueDictionary(string prefix, object o) 
    : this(prefix, new RouteValueDictionary(o)) 
    { } 

    public PrefixedRouteValueDictionary(string prefix, IDictionary<string, object> d) 
    : base(d.ToDictionary(kvp=>(prefix ?? "") + kvp.Key, kvp => kvp.Value)) 
    { } 
} 

तुम अब क्या कर सकते हैं:

Html.ActionLink( 
    item.Message, 
    "Index", 
    "Home", 
    new PrefixedRouteValueDictionary("Filter.", 
    new FilterViewModel() { MessageFilter = item.Message }), 
    null); 

हालांकि, यह चेतावनी है कि Add, Remove, TryGetValue और this[string key]prefix को ध्यान में रखने के लिए विधियों को परिवर्तित नहीं किया गया है। यह उन तरीकों के new संस्करणों को परिभाषित करके हासिल किया जा सकता है, लेकिन क्योंकि वे वर्चुअल नहीं हैं, वे केवल कॉलर्स से काम करेंगे जो जानते हैं कि वे RouteValueDictionary के बजाय PrefixedRouteValueDictionary से बात कर रहे हैं।

+0

यह मेरे शुरुआती विचार के समान था। एक अतिरिक्त चेतावनी यह है कि आप केवल एक एक्शनलिंक विधि कॉल के लिए एक उपसर्ग कर सकते हैं और सभी वस्तुओं को उपसर्ग होना होगा। मैंने अपनी जरूरतों को सटीक जरूरतों और विचारों के आधार पर एक और संभावित समाधान के साथ अपडेट किया है जिसमें आपको रुचि हो सकती है। चीयर्स। – Craig

2

दिलचस्प प्रश्न (+1)। मुझे लगता है कि उद्देश्य क्वेरीस्ट्रिंग पैरामीटर को अपने Action पैरामीटर में बाध्य करने के लिए डिफ़ॉल्ट मॉडल बाइंडर का उपयोग करना है।

बॉक्स में से मुझे विश्वास नहीं है कि ActionLink विधि आपके लिए यह करेगी (बेशक आपके पास खुद को रोल करने से रोक नहीं है)। परावर्तक में देखकर हम देख सकते हैं कि objectRouteValueDictionary में जोड़ा गया है, केवल महत्वपूर्ण मान जोड़े जोड़े गए हैं। यह वह कोड है जो कुंजी मान जोड़े जोड़ता है और जैसा कि आप देख सकते हैं कि ऑब्जेक्ट गुणों का कोई ट्रैवर्स नहीं है।

foreach (PropertyDescriptor descriptor in TypeDescriptor.GetProperties(values)) 
{ 
    object obj2 = descriptor.GetValue(values); 
    this.Add(descriptor.Name, obj2); 
} 
अपने वस्तु

var values = new { Filter = new Filter { MessageFilter = item.Message } } 

कुंजी जोड़ा जा रहा है Filter है और मूल्य अपने Filter वस्तु जो अपने ऑब्जेक्ट प्रकार के पूरी तरह से योग्य नाम के मूल्यांकन करेंगे है के लिए

तो।

इसका परिणाम Filter=Youre.Namespace.Filter है।

संपादितसंभव अपने सटीक आवश्यकताओं के आधार पर


एक्सटेंशन विधिसमाधान करता है काम

ध्यान दें कि यह स्थिर ढांचे तरीकों का उपयोग करता ExpressionHelper और ModelMetadata (जो मौजूदा सहायकों द्वारा भी उपयोग किया जाता है) उचित नाम निर्धारित करने के लिए डिफ़ॉल्ट मॉडल बाइंडर क्रमशः संपत्ति का समझ और मूल्य समझ जाएगा।

public static class ExtentionMethods 
{ 
    public static MvcHtmlString ActionLink<TModel, TProperty>(
     this HtmlHelper<TModel> helper, 
     string linkText, 
     string actionName, 
     string controllerName, 
     params Expression<Func<TModel, TProperty>>[] expressions) 
    { 
     var urlHelper = new UrlHelper(helper.ViewContext.HttpContext.Request.RequestContext); 

     var url = urlHelper.Action(actionName, controllerName); 

     if (expressions.Any()) 
     { 
      url += "?"; 

      foreach (var expression in expressions) 
      { 
       var result = ExpressionHelper.GetExpressionText(expression); 

       var metadata = ModelMetadata.FromLambdaExpression<TModel, TProperty>(expression, helper.ViewData); 

       url = string.Concat(url, result, "=", metadata.SimpleDisplayText, "&"); 
      } 

      url = url.TrimEnd('&'); 
     } 

     return new MvcHtmlString(string.Format("<a href='{0}'>{1}</a>", url, linkText)); 
    } 
} 

नमूना मॉडल

public class MyViewModel 
{ 
    public string SomeProperty { get; set; } 

    public FilterViewModel Filter { get; set; } 
} 

public class FilterViewModel 
{ 
    public string MessageFilter { get; set; } 
} 

कार्रवाई

public ActionResult YourAction(MyViewModel model) 
{ 
    return this.View(
     new MyViewModel 
     { 
      SomeProperty = "property value", 
      Filter = new FilterViewModel 
      { 
       MessageFilter = "stuff" 
      } 
     }); 
} 

प्रयोग

विधि के उस अंतिम params पैरामीटर के माध्यम से क्वेरी दृश्य में आपकी दृश्य मॉडल गुणों में से कोई भी जोड़ा जा सकता है।

@this.Html.ActionLink(
    "Your Link Text", 
    "YourAction", 
    "YourController", 
    x => x.SomeProperty, 
    x => x.Filter.MessageFilter) 

मार्कअप

<a href='/YourAction/YourController?SomeProperty=some property value&Filter.MessageFilter=stuff'>Your Link Text</a> 

इसके बजाय string.Format का उपयोग कर आप TagBuilder इस्तेमाल कर सकते हैं की , क्वेरी स्ट्रिंग सुरक्षित रूप से एक यूआरएल में पारित होने के लिए इनकोडिंग किया जाना चाहिए और इस विस्तार विधि कुछ अतिरिक्त सत्यापन की आवश्यकता होगी, लेकिन मुझे लगता है कि यह उपयोगी हो सकता है। ध्यान दें कि, हालांकि यह एक्सटेंशन विधि एमवीसी 4 के लिए बनाई गई है, लेकिन इसे पिछले संस्करणों के लिए आसानी से संशोधित किया जा सकता है। मुझे एहसास नहीं हुआ कि एमवीसी टैग में से एक अब तक संस्करण 3 के लिए था।

+0

* निश्चित रूप से आपको अपना खुद का रोल करने से रोक नहीं रहा है * - और मैं यह कैसे कर सकता हूं? :) और आप सही हैं, मैं "फ़िल्टर = आपका नाम ..." देख रहा था। – DaveShaw

+0

@ डेवशॉ हालांकि आप सहमत नहीं हो सकते हैं, मुझे लगता है कि यह आपके प्रश्न का एक मूल्यवान उत्तर है। खुश होती है। – Craig

+0

@ डेवशॉ इस बारे में घर से काम करने के बारे में सोच रहा था और उस पर एक झटका लगा। जब आप इसके साथ काम करते हैं तो यह समाधान परिपक्व हो सकता है लेकिन मुझे लगता है कि यह उपयोगी हो सकता है। – Craig

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