2012-04-04 61 views
6

我有一個視圖模型與過濾器屬性,有,​​我用它來篩選我的數據如何使用屬性創建的ActionLink的視圖模型

例如,許多特性:

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的。

我曾嘗試:

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

我也試過routeValues參數設置爲:

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

但這些不生成查詢字符串像上面一個。

+0

+1好問題 – 2012-04-04 12:59:37

+0

感謝您的編輯;我重構了答案,並在替換中忘記添加'前綴'! – 2012-04-04 13:22:21

+0

@AndrasZoltan沒問題。 – DaveShaw 2012-04-04 13:28:58

回答

1

你可以從一個FilterViewModel實例創建一個RouteValueDictionary,然後使用上ToDictionary傳遞給另一個RouteValues與'Filter.'前綴的所有鍵。

進一步考慮它,你可以構建的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,TryGetValuethis[string key]方法不會考慮到prefix。這可以通過定義這些方法的new版本來實現,但由於它們不是虛擬的,它們只能從知道他們正在與PrefixedRouteValueDictionary而不是RouteValueDictionary對話的呼叫者那裏工作。

+0

這和我最初的想法很相似。另外需要注意的是,每個ActionLink方法調用只能有一個前綴,所有項都必須有前綴。我用另一種可能的解決方案更新了我的答案,具體取決於確切的需求和您可能感興趣的想法乾杯。 – Craig 2012-04-05 21:09:08

2

有趣的問題(+1)。我假設目的是使用默認模型聯編程序將查詢字符串參數綁定到您的參數Action

開箱即用,我不認爲ActionLink方法會爲您做到這一點(當然,沒有任何東西阻止您自己滾動)。查看反射器,我們可以看到,當object被添加到RouteValueDictionary時,只有鍵值對被添加。這是添加鍵值對的代碼,正如你所看到的,沒有遍歷對象屬性。

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

編輯根據您的具體需求


擴展方法可能的解決方案做的工作

注意,它使用靜態框架方法ExpressionHelperModelMetadata(其也由現有的助手使用)來確定合適的名稱默認模型綁定器將分別理解和評估屬性。

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的,查詢字符串應該被編碼爲在URL中安全地過去了,這個擴展方法將需要一些額外的驗證,但我認爲這可能會有用。還要注意的是,雖然這個擴展方法是爲MVC 4構建的,但它可以很容易地修改爲以前的版本。我沒有意識到,其中一個MVC標籤是第3版到現在。

+0

*當然,沒有任何東西阻止你滾動自己* - 我該怎麼做? :)你說得對,我看到「Filter = Your.Nam ...」。 – DaveShaw 2012-04-04 13:07:00

+0

@DaveShaw雖然你可能不同意,但我覺得這是對你的問題有價值的答案。乾杯。 – Craig 2012-04-04 13:09:13

+0

@DaveShaw在我下班回家的路上想到了這件事,並對它進行了刺探。這個解決方案可以在你使用它時成熟,但我認爲它可能有用。 – Craig 2012-04-05 02:19:01

相關問題