2017-09-19 82 views
1

RouteValues传递IEnumerable的财产想象的对象定义如下:在ActionLink的

public class MyViewModel{ 
    public List<string> MyList { get; set; } 
} 

在我看来,我有这个动作链接:

@Ajax.ActionLink("<", "Index", new MyViewModel() { MyList = new List<string>() {"foo", "bar"}}, new AjaxOptions()) 

的ActionLink的的HTML结果将是:

<a class="btn btn-default" data-ajax="true" href="/Index?MyList=System.Collections.Generic.List%601%5BSystem.String%5D">&lt;</a> 

我的问题是,如何得到这个结果:

<a class="btn btn-default" data-ajax="true" href="/Index?MyList=foo&MyList=bar">&lt;</a> 

回答

1

随着斯蒂芬的思想,我开发了一个帮手扩展方法来做到这一点。

小心URL查询字符串限制:如果集合的值太多,则URL可能会大于255个字符并引发异常。

public static class AjaxHelperExtensions 
{ 
    public static MvcHtmlString ActionLinkUsingCollection(this AjaxHelper ajaxHelper, string linkText, string actionName, object model, AjaxOptions ajaxOptions, IDictionary<string, object> htmlAttributes) 
    { 
     var rv = new RouteValueDictionary(); 
     foreach (var property in model.GetType().GetProperties()) 
     { 
      if (typeof(ICollection).IsAssignableFrom(property.PropertyType)) 
      { 
       var s = ((IEnumerable<object>)property.GetValue(model)); 
       if (s != null && s.Any()) 
       { 
        var values = s.Select(p => p.ToString()).Where(p => !string.IsNullOrEmpty(p)).ToList(); 
        for (var i = 0; i < values.Count(); i++) 
         rv.Add(string.Concat(property.Name, "[", i, "]"), values[i]); 
       } 
      } 
      else 
      { 
       var value = property.GetGetMethod().Invoke(model, null) == null ? "" : property.GetGetMethod().Invoke(model, null).ToString(); 
       if (!string.IsNullOrEmpty(value)) 
        rv.Add(property.Name, value); 
      } 
     } 
     return AjaxExtensions.ActionLink(ajaxHelper, linkText, actionName, rv, ajaxOptions, htmlAttributes); 
    } 
} 
+0

不能仅仅使用带有方法GET和隐藏值的表单吗?这似乎比你的扩展更简单 – Shoe

+0

是的,我可以,但我有4个链接/意见。使用帮手更“漂亮” – GGO

1

您不能使用@Html.ActionLink()为集合生成路由值。该方法(以及所有生成url的MVC方法)在内部使用该属性的.ToString()方法来生成路由/查询字符串值(因此您的MyList=System.Collections.Generic.List%601%5BSystem.String%5D"结果)。

该方法不会对复杂的属性或集合进行递归 - 除了丑陋的查询字符串外,您可以轻松地超出查询字符串限制并引发异常。

它不清楚你为什么要这样做(通常的方法是传递对象的ID,然后再根据ID在GET方法中获取数据),但是你可以通过创建一个带索引属性名称的RouteValueDictionary,并在您的@Ajax.ActionLink()方法中使用它。

在视图

@{ 
    var rvd = new RouteValueDictionary(); 
    rvd.Add("MyList[0]", "foo"); 
    rvd.Add("MyList[1]", "bar"); 
} 
@Ajax.ActionLink("<", "Index", rvd, new AjaxOptions()) 

这将使A到

public ActionResult Index(MyViewModel model) 

但是你还必须让MyList一个属性(在DefaultModelBinder不绑定字段)

public class MyViewModel{ 
    public List<string> MyList { get; set; } // add getter/setter 
} 

然后POST方法中的model.MyList的值将为b e ["foo", "bar"]

+0

谢谢斯蒂芬,这是一个表单过滤器,没有MyList集合中的很多项目,但我保持警告关于查询字符串限制!我们有任何方法可以自动执行RouteValueDictionary转换吗?我会尝试使用反射来开发一个例子 – GGO

+1

那么你可以编写自己的扩展方法来完成它。但是你的问题只是显示了2个硬编码值,所以现在还不清楚你真正想要的是什么 –