如何创建与视图模型属性的ActionLink的(How to create an ActionLin

2019-09-16 08:35发布

我有有,我用它来筛选我的数据很多属性筛选器属性视图模型

例:

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, }, },

但这些不生成查询字符串像上面一个。

Answer 1:

你可以从一个创建RouteValueDictionary FilterViewModel实例,然后使用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); 

需要说明的这一点,不过,是的AddRemoveTryGetValuethis[string key]方法不改变,以顾及prefix 。 这可以通过定义来实现new的这些方法的版本,而是因为他们不是虚拟的,他们会只从知道他们在说一个呼叫者工作PrefixedRouteValueDictionary而不是RouteValueDictionary



Answer 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版本到现在为止。



文章来源: How to create an ActionLink with Properties for the View Model