eine Ansicht Modell wie folgt gegeben:Html.Labelfor verwenden Display des Objekts nicht Eigentum
public class ParentViewModel
{
public object ChildViewModel { get; set; }
}
Wenn ich Html.LabelFor
wie folgt verwenden:
@Html.LabelFor(model => model.ChildViewModel)
ich eine Ausgabe wie diese bekommen würde:
<label for="Model_ChildViewModel">ChildViewModel</label>
Was ich eigentlich will, ist, dass das generierte Etikett das Attribut DisplayName
verwendet, auf das angewendet wird das Objekt E.G.
[DisplayName("My Custom Label")]
public class ChildViewModel
{
}
mit einer Leistung von:
<label for="Model_ChildViewModel">My Custom Label</label>
Ich verstehe, dass die Html.LabelFor
Methode einen Ausdruck kommt, das eine Eigenschaft erwartet und es wird auf dieser Eigenschaft für das DisplayName
Attribut suchen, anstatt das Objekt selbst.
Ich habe eine HTML-Helper-Methode zu erreichen, was geschaffen Ich möchte, dass dies wie folgt aussieht:
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());
}
Statt einen Ausdruck zu nehmen, mein Helfer ein Func<TModel, object>
nimmt, die das Objekt zurückgibt, die ich für die überprüfen möchten DisplayName
Attribut.
Das erste Problem, das ich hatte, war, als ich so diese Methode in Rasierapparat zu rufen versucht:
@Html.CreateLabel(model => model.ChildObject)
bekomme ich folgende Fehlermeldung:
The type arguments for method 'CreateLabel<TModel>(this HtmlHelper,
Func<TModel, object>) cannot be inferred from usage. Try specifying
the arguments explicitly.'
wie dies So nenne ich die Methode statt :
@{ Html.CreateLabel<ChildViewModel>(model => model.ChildObject); }
aber nichts wird gerendert. Wenn ich den Debugger verwende, um meine Hilfsmethode zu durchlaufen, wird das Label-Tag generiert, aber es wird nichts angezeigt, wenn meine Seite gerendert wird.
Also meine Fragen sind:
- Wie behebe ich das das Etikett meiner Ansicht zu generieren?
- Was muss ich tun, damit der generische Parameter abgeleitet werden kann?
- Gibt es eine Möglichkeit, den HTML-Helfer zu schreiben, um dasselbe zu tun, aber einen Ausdruck zu verwenden? Ich habe keine Erfahrung mit Ausdrücke, also weiß nicht, wo ich anfangen soll.
aktualisieren
Ich dachte, ich den endgültigen Code schreiben würde, wie ich ein paar kleinere Änderungen vorgenommen. Zunächst habe ich mir die Helfer im MVC-Quellcode angeschaut und beschlossen, die Methode in drei separate Methoden aufzuteilen. Ich entfernte auch alle TagBuilder
Sachen, da alles, was ich wirklich brauchte, war, den Text zu erzeugen, der zwischen den <legend></legend>
Tags eingespritzt werden sollte. Der endgültige Code ist unten. Noch einmal, Danke an Sylon, dass er mir dabei geholfen hat.
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;
}
}
Danke, funktioniert wunderbar. Ich wusste, dass ich das eigentliche Objekt aus dem Ausdruck holen musste, aber ich wusste nicht, wie ich es machen sollte, daher ist diese Zeile 'expression.Compile(). Invoke (html.ViewData.Model)' besonders hilfreich. –