的給定視圖模型是這樣的:Html.Labelfor使用DisplayName的對象不是財產
public class ParentViewModel
{
public object ChildViewModel { get; set; }
}
如果我使用Html.LabelFor
這樣的:
@Html.LabelFor(model => model.ChildViewModel)
我會得到一個輸出這樣的:
<label for="Model_ChildViewModel">ChildViewModel</label>
我真正想要的是,雖然是生成的標籤使用DisplayName
屬性應用於對象E.G.
[DisplayName("My Custom Label")]
public class ChildViewModel
{
}
用的輸出:
<label for="Model_ChildViewModel">My Custom Label</label>
據我所知,Html.LabelFor
方法需要一個期望的性質的表達式,它會檢查是否有與該屬性而不是對象本身的屬性DisplayName
。
我已經創建了一個HTML輔助的方法來達到我想要的東西,看起來像這樣:
public static IHtmlString CreateLabel<TModel>(this HtmlHelper html, Func<TModel, object> func)
where TModel : class
{
TagBuilder tb = new TagBuilder("label");
var model = html.ViewData.Model as TModel;
if (model != null)
{
object obj = func(model);
if (obj != null)
{
var attribute = obj.GetType().GetCustomAttributes(
typeof(DisplayNameAttribute), true)
.FirstOrDefault() as DisplayNameAttribute;
if (attribute != null)
{
tb.InnerHtml = attribute.DisplayName;
return MvcHtmlString.Create(tb.ToString());
}
else
{
tb.InnerHtml = obj.ToString();
return MvcHtmlString.Create(tb.ToString());
}
}
}
tb.InnerHtml = html.ViewData.Model.ToString();
return MvcHtmlString.Create(tb.ToString());
}
而不是採取一種表達,幫助我需要一個Func<TModel, object>
返回,我要檢查的對象DisplayName
屬性。
我是當我試圖調用此方法在剃刀這樣的第一個問題:
@Html.CreateLabel(model => model.ChildObject)
我收到以下錯誤:
The type arguments for method 'CreateLabel<TModel>(this HtmlHelper,
Func<TModel, object>) cannot be inferred from usage. Try specifying
the arguments explicitly.'
因此,我調用該方法是這樣而不是:
@{ Html.CreateLabel<ChildViewModel>(model => model.ChildObject); }
但沒有任何東西被渲染。如果我使用調試器來遍歷我的幫助器方法,那麼會生成標籤標籤,但是當我的頁面呈現時,不會顯示任何內容。
所以我的問題是:
- 我該如何解決這個問題,生成的標籤我的看法?
- 我需要做些什麼才能推斷泛型參數?
- 有什麼辦法可以編寫Html幫助器來做同樣的事情,但使用表達式嗎?我沒有使用表達式的經驗,所以不知道從哪裏開始。
更新
我想我會發布最終的代碼,因爲我做了一些小的改動。首先,我查看了MVC源代碼中的助手,並決定將該方法拆分爲三個獨立的方法,與提供的示例一致。我也刪除了所有TagBuilder
的東西,因爲我真正需要的是生成要在<legend></legend>
標籤之間注入的文本。最終的代碼如下。再次感謝Sylon幫助我解決這個問題。
public static IHtmlString LegendTextFor<TModel, TObject>(this HtmlHelper<TModel> html, Expression<Func<TModel, TObject>> expression)
{
return LegendTextHelper(html,
ModelMetadata.FromLambdaExpression(expression, html.ViewData),
ExpressionHelper.GetExpressionText(expression),
expression.Compile().Invoke(html.ViewData.Model));
}
private static IHtmlString LegendTextHelper<TModel, TObject>(this HtmlHelper<TModel> html, ModelMetadata metadata, string htmlFieldName, TObject value)
{
string resolvedLabelText = metadata.DisplayName ?? value.GetDisplayName() ?? metadata.PropertyName ?? htmlFieldName.Split('.').Last();
if (String.IsNullOrEmpty(resolvedLabelText))
return MvcHtmlString.Empty;
return MvcHtmlString.Create(resolvedLabelText);
}
private static string GetDisplayName<T>(this T obj)
{
if (obj != null)
{
var attribute = obj.GetType()
.GetCustomAttributes(typeof(DisplayNameAttribute), false)
.Cast<DisplayNameAttribute>()
.FirstOrDefault();
return attribute != null ? attribute.DisplayName : null;
}
else
{
return null;
}
}
謝謝你,精美的作品。我知道我必須從表達式中得到實際的對象,但不知道如何去做,所以這行'expression.Compile()。Invoke(html.ViewData.Model)'特別有用。 –