Каков самый простой способ получить значение свойства из переданного выражения лямбда в методе расширения для HtmlHelper?
Я пишу грязный метод расширения для HtmlHelper, чтобы я мог сказать что-то вроде HtmlHelper.WysiwygFor(лямбда) и отобразить 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;
}
Спасибо!
Ответы
Ответ 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());
}
Ответ 2
ModelMetadata metadata = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);
Object value = metadata.Model;
String name = metadata.PropertyName;
Ответ 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
Это не рассматривается ни Питером, ни БигМоммой, но он сочетает в себе оба. Если вы вызываете это из метода контроллера, где у вас нет доступа к экземпляру 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;