web-dev-qa-db-fra.com

Quelle est la manière la plus simple d'obtenir la valeur d'une propriété à partir d'une expression lambda passée dans une méthode d'extension pour HtmlHelper?

J'écris une petite méthode d'extension sale pour HtmlHelper afin que je puisse dire quelque chose comme HtmlHelper.WysiwygFor (lambda) et afficher le CKEditor.

J'ai ce travail actuellement, mais il semble un peu plus lourd que je ne le préférerais. J'espère qu'il y a une manière plus simple de procéder.

Voici ce que j'ai jusqu'à présent.

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

Merci!

54
Andrew Siemer

Essayez comme ceci:

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());
}
83
Darin Dimitrov
ModelMetadata metadata = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);
Object value = metadata.Model;
String name = metadata.PropertyName;
25
Peter Hedberg

Je sais que c'est un vieux fil mais juste au cas où quelqu'un le chercherait, la façon de générer l'attribut id/name est aussi:

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

J'utilise ceci dans mes extensions et je n'ai jamais eu de problème avec ça. Il fonctionne également très bien avec les propriétés imbriquées.

10

Le moyen le plus simple est de tout résumer dans une méthode d'extension:

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

}

La syntaxe d'appel est donc:

expression.Value(htmlHelper.ViewData)
5
BigMomma

Futures ASP.NET MVC inclut un assistant pour cela.

2
user571646

Ce n'est pas traité par la réponse de Peter ou de BigMomma, mais il combine les deux. Si vous appelez cela à partir d'une méthode de contrôleur, où vous n'avez pas accès à une instance HtmlHelper, créez simplement une méthode de contrôleur de base comme ceci:

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 ) );
}

Ensuite, vous pouvez lire ce dont vous avez besoin dans les métadonnées du modèle, comme d'habitude;

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