2012-04-04 69 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