【问题标题】:What is the easiest way to get the property value from a passed lambda expression in an extension method for HtmlHelper?从 HtmlHelper 的扩展方法中传递的 lambda 表达式中获取属性值的最简单方法是什么?
【发布时间】:2011-02-20 06:22:56
【问题描述】:

我正在为 HtmlHelper 编写一个肮脏的小扩展方法,以便我可以说类似 HtmlHelper.WysiwygFor(lambda) 并显示 CKEditor。

我目前有这个工作,但它似乎比我希望的要麻烦一些。我希望有更直接的方法来做到这一点。

这是我目前所拥有的。

public static MvcHtmlString WysiwygFor<TModel, TProperty>(this HtmlHelper<TModel> helper, Expression<Func<TModel, TProperty>> expression)
{
    return MvcHtmlString.Create(string.Concat("<textarea class=\"ckeditor\" cols=\"80\" id=\"",
                                        expression.MemberName(), "\" name=\"editor1\" rows=\"10\">", 
                                        GetValue(helper, expression),
                                        "</textarea>"));
}

private static string GetValue<TModel, TProperty>(HtmlHelper<TModel> helper, Expression<Func<TModel, TProperty>> expression)
{
    MemberExpression body = (MemberExpression)expression.Body;
    string propertyName = body.Member.Name;
    TModel model = helper.ViewData.Model;
    string value = typeof(TModel).GetProperty(propertyName).GetValue(model, null).ToString();
    return value;
}

private static string MemberName<T, V>(this Expression<Func<T, V>> expression)
{
    var memberExpression = expression.Body as MemberExpression;
    if (memberExpression == null)
            throw new InvalidOperationException("Expression must be a member expression");

    return memberExpression.Member.Name;
}

谢谢!

【问题讨论】:

  • 我测试了你的 Getvalue 方法,当助手是一个选择列表时得到了很好的结果。在这种情况下,这里的其他方法都失败了。

标签: asp.net-mvc recursion lambda extension-methods html-helper


【解决方案1】:

试试这样:

public static MvcHtmlString Try<TModel, TProperty>(
    this HtmlHelper<TModel> htmlHelper, 
    Expression<Func<TModel, TProperty>> expression
)
{
    var builder = new TagBuilder("textarea");
    builder.AddCssClass("ckeditor");
    builder.MergeAttribute("cols", "80");
    builder.MergeAttribute("name", "editor1");
    builder.MergeAttribute("id", expression.Name); // not sure about the id - verify
    var value = ModelMetadata.FromLambdaExpression(
        expression, htmlHelper.ViewData
    ).Model;
    builder.SetInnerText(value.ToString());
    return MvcHtmlString.Create(builder.ToString());
}

【讨论】:

  • 我最感兴趣的是上面的这一行 - var value = ModelMetadata.FromLambdaExpression( expression, htmlHelper.ViewData ).Model;效果很好!我确实发现您的 expression.Name 返回 null。我将其交换为指向我的 MemberName 方法以使其适用于 ID。另外,我发现有一个 TagBuilder.GenerateId() 用于添加 ID 属性。谢谢。我一定会在我即将出版的书中提到你(ASP.NET MVC Cookbook - groups.google.com/group/aspnet-mvc-2-cookbook-review
  • 嘿达林,你能解释一下这行吗? var value = ModelMetadata.FromLambdaExpression( expression, htmlHelper.ViewData ).Model;
【解决方案2】:
ModelMetadata metadata = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);
Object value = metadata.Model;
String name = metadata.PropertyName;

【讨论】:

  • 这对我有用,并通过 PropertyName 正确获取属性名称,其中 expression.Name 返回 null。编辑添加 - 我正在运行 MVC5 以防万一
【解决方案3】:

我知道这是一个旧线程,但以防万一有人在寻找它,生成 id / name 属性的方法也是:

System.Web.Mvc.ExpressionHelper.GetExpressionText(expression);

我在我的扩展程序中使用它并且从未遇到任何问题。它也适用于嵌套属性。

【讨论】:

  • 这将获得属性的名称,而不是它的值
【解决方案4】:

最简单的方法是将其全部包装在一个扩展方法中:

public static class ExtensionMethods
{   

    public static object Value<TModel, TProperty>(this Expression<Func<TModel, TProperty>> expression, ViewDataDictionary<TModel> viewData)
    {
        return ModelMetadata.FromLambdaExpression(expression, viewData).Model;
    }  

}

所以调用语法是:

expression.Value(htmlHelper.ViewData)

【讨论】:

    【解决方案5】:

    ASP.NET MVC 3 Futures 包含一个帮助器。

    【讨论】:

      【解决方案6】:

      彼得或 BigMomma 的回答都没有解决这个问题,但它结合了两者。如果您从一个控制器方法调用它,而您无法访问 HtmlHelper 实例,则只需创建一个基本控制器方法,如下所示:

      public ModelMetadata GetModelMetadata<TModel, TProperty>( TModel model, Expression<Func<TModel, TProperty>> expression )
      {
          ViewData.Model = model; //model is null in Controller; you must set it here (or earlier) in order to extract values from the returned ModelMetadata.
          return ModelMetadata.FromLambdaExpression( expression, new ViewDataDictionary<TModel>( ViewData ) );
      }
      

      然后你就可以像往常一样从模型元数据中读取你需要的东西了;

      var mm = GetModelMetaData( model, m => m.SomeProperty );
      string name = mm.PropertyName;
      object value = mm.Model;
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-07-12
        • 2015-06-22
        • 2013-12-22
        • 2012-06-18
        • 2020-10-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多