Frage

Ich schreibe eine MVC2 App DataAnnotations. Ich habe folgendes Modell:

public class FooModel 
{
    [ScaffoldColumn("false")]
    public long FooId { get; set; }

    [UIHint("BarTemplate")]
    public DateTime? Bar { get; set;}
}

Ich möchte eine benutzerdefinierte Anzeigevorlage für Bar erstellen. Ich habe folgende Vorlage erstellt:

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<DateTime?>" %>

<div class="display-label">
    <span><%: Html.LabelForModel() %></span>
</div>
<div class="display-field">
    <span><%: Html.DisplayForModel()%></span>
    <%: Html.ActionLink("Some link", "Action", new { id = ??FooId?? }) %>
</div>

Nun, mein Problem ist, dass innerhalb Vorlage für Bar ich eine andere Eigenschaft von meinem Modell zugreifen möchten . Ich möchte nicht, eine eigene Vorlage für FooModel schaffen, weil, als ich alle anderen FooModel Eigenschaften müssen hart codieren.

Nach einer kurzen Untersuchung mit einem Debugger kann ich sehen, dass:

  1. this.ViewData.ModelMetadata.ContainerType FooModel ist (wie erwartet)
  2. this.ViewData.TemplateInfo hat ein Nicht-öffentliches Eigentum VisitedObjects (Vom Typ System.Collections.Generic.HashSet<object>) Welche enthält zwei Elemente: FooModel und DateTime?.

Wie kann ich Zugriff auf meine FooModel bekommen? Ich will nicht meine Art und Weise hacken um Reflexion verwendet wird.

Update:

Ich habe mootinator Antwort akzeptiert, da sie als die beste Lösung für mich sieht, die Typsicherheit ermöglicht. Ich habe auch Tx3 Antwort, wie mootinator Antwort baut auf sie upvoted. Dennoch denke ich, dass es eine bessere Unterstützung Form MVC in dieser Art von Szenarien sein sollte, die meiner Meinung nach durchaus üblich sind in der realen Welt, sondern von Beispielanwendungen fehlt.

War es hilfreich?

Lösung

Sorry, wenn dieser Vorschlag scheint bescheuert, ich habe es nicht versucht, konnte aber nicht, dass Sie das tun, was Tx3 vorgeschlagen, ohne einen Haufen neuer Klassen zu schaffen, die durch eine generische Klasse zu definieren Referenz unabhängig von der Art der Eltern wünschen Sie?

    public class FooModel 
    {
        [ScaffoldColumn("false")]
        public long FooId { get; set; }

        [UIHint("BarTemplate")]
        public ParentedDateTime<FooModel> Bar { get; set;}

        public FooModel()
        {
            Bar = new ParentedDateTime<FooModel>(this);
        }
    }


    public class ParentedDateTime<T>
    {
        public T Parent {get; set;}
        public DateTime? Babar {get; set; }

        public ParentedDateTime(T parent)
        {
            Parent = parent;
        }

}

Sie könnten erweitern, dass alle alten Typ mit einem <Parent, Child> einzukapseln generic getippt, auch.

Das würde man auch den Vorteil geben, dass Ihre stark typisierte Vorlage für sein würde

Inherits="System.Web.Mvc.ViewUserControl<ParentedDateTime<FooType>> so würden Sie nicht explizit Namen haben, die Vorlage überall zu verwenden. Das ist mehr, wie es an der Arbeit gedacht ist.

Andere Tipps

Vielleicht könnten Sie neue Klasse erstellen, lassen Sie uns sagen UserDateTime und es würde auf NULL festlegbare Datetime enthalten und der Rest der Informationen, die Sie benötigen. Dann würden Sie benutzerdefinierte Anzeigevorlage für UserDateTime verwenden und erhalten Sie Zugang zu Informationen, die Sie benötigen.

Ich weiß, dass Sie sich für eine andere Art von Lösung könnte suchen.

Ich denke, man kann besser aus sein, diese Funktionalität zu einem Htmlhelper Anruf von der übergeordneten Ansicht zu extrahieren.

So etwas wie RenderSpecialDateTime<TModel>(this HtmlHelper html, Expression<Func<TModel,DateTime?>> getPropertyExpression) würde wahrscheinlich den Job.

Andernfalls werden Sie so etwas wie zu tun, was Tx3 vorgeschlagen. Ich upvoted seine Antwort, aber gepostet als Alternative.

Könnten Sie nicht verwenden, um das Viewdata Dictionary-Objekt in der Steuerung und dann in der Viewusercontrol greifen das? Es wäre nicht stark typisiert werden, aber ... Sie einen Helfer nichts zu tun schreiben könnten, wenn es leer ist, und Link, um die Beispiel Login Geschichte Seite zu sagen, wenn es einen Wert hat.

Es scheint, dass irgendwo zwischen MVC 5.0 und 5.2.2 eine „Container“ Eigenschaft wurde auf die ModelMetadata Klasse hinzugefügt.

Da jedoch alle Methoden in einem Anbieter für Metadatenerstellung (GetMetadataForProperty, erstellen usw.) haben keine Behälter in ihre Unterschrift wird die Container-Eigenschaft nur in bestimmten Fällen zugeordnet (GetMetadataForProperties und GetMetadataFromProvider nach reflektiertes Code) und in meinem Fall war in der Regel null.

Also, was ich am Ende tun wird, um das GetMetadataForProperty in einem neuen Metadaten-Anbietern überschreiben und dort Einstellung:

public override ModelMetadata GetMetadataForProperty(Func<object> modelAccessor, Type containerType, string propertyName)
{
  var propMetaData = base.GetMetadataForProperty(modelAccessor, containerType, propertyName);
  Object container = modelAccessor.Target.GetType().GetField("container").GetValue(modelAccessor.Target);
  propMetaData.Container = container;
  return propMetaData;
}

Ich weiß, dass diese Reflexion ist, aber es ist ziemlich prägnant. Es scheint, dass MS diese Over ist die Korrektur so wird es vielleicht möglich sein, die Reflexion Code in der Zukunft zu ersetzen.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top