2010-01-25 5 views
8

In der Site, die ich erstelle, muss ich Datetime-Eigenschaften in verschiedene Kombinationen aufgeteilt haben, abhängig von der Eigenschaft. Beispiele:ASP.NET MVC 2 Benutzerdefinierte Editorvorlagen zum Teilen von Datetime-Feldern

-Mitglied hat Geburtsdatum Eigenschaft, die für die Sicht als seperate Tag/Monat/Jahr Dropdown-Listen angezeigt werden muss.

eine Kreditkarte Ansicht hat ein Ablaufdatum Eigenschaft, die als separate Monat/Jahr Dropdown-Listen angezeigt werden muss.

Eine Exkursionsansicht hat eine Eigenschaft nur für die Zeit, in der Stunden und Minuten als Textfelder benötigt werden.

Jedes dieser Szenarien erfordert eine Validierung und idealerweise auch eine Validierung auf der Client-Seite.

Ich habe bei verschiedenen Optionen wie benutzerdefinierte Bindung, benutzerdefinierte Attribute geschaut und jetzt bin auf der Suche Vorlagen benutzerdefinierten Editor, aber bisher habe ich bei der Suche nach geeigneten Lösungen wenig Glück gehabt.

Es scheint wie eine gemeinsame Aufgabe, aber die Suche im Netz hat wenig gezeigt, die alles abdeckt (insbesondere mit dem Validierungselement).

Also meine Frage ist, hat jemand anderes geschafft, das oben genannte zu erreichen?

(Daumen!)

+0

„aber bisher habe ich bei der Suche nach geeigneten Lösungen wenig Glück gehabt.“ Was bedeutet das? – jfar

+0

Hi jfar, ich bin ziemlich neu in C# und mvc und habe mich daher auf Google-Suchen verlassen, um einen guten Ausgangspunkt für eine Lösung zu finden. Die wichtigste davon ist http://www.hanselman.com/blog/SplittingDateTimeUnitTestingASPNETMVCCustomModelBinders.aspx gewesen, aber ich kann nicht herausfinden, wie die Validierung (Server-Seite oder Client-Seite) hinzuzufügen. –

+0

Oh ok, ich dachte es wäre etwas anderes. Wenn nicht jemand anders antwortet, werde ich heute Nacht eine Antwort schreiben. Ich mache diese Art von Ding die ganze Zeit. – jfar

Antwort

13

Ok, ich werde versuchen, Sie 90% des Weg dorthin zu bekommen. Dies ist eigentlich ein großer und komplexer Teil von MVC 2 und in dieser Antwortbox fast unmöglich zu beantworten.

Jetzt sollten Sie zuerst zum Brad Wilsons Blog gehen und ausführlich lesen, wie Sie die Standard-MVC 2-Vorlagen anpassen können. Das sollte Ihnen ein viel klareres Verständnis aller beweglichen Teile geben.

http://bradwilson.typepad.com/blog/2009/10/aspnet-mvc-2-templates-part-1-introduction.html

Jetzt werde ich ein einfaches Beispiel beginnen, wie ein erfundenen Termin View-Modell zu schaffen, in dem wir geliefert, dass die Werten machen wollen in der Zeit nicht zurückgehen. Achte jetzt nicht auf die Attribute, wir werden es schaffen.

Hier ist das Viewmodel Ich verwende:

public class AppointmentViewModel 
{ 
    [Required] 
    public string Name { get; set; } 

    [CantGoBackwardsInTime] 
    public DateRange DateRange { get; set; } 
} 

public class DateRange 
{ 
    public DateTime Start { get; set; } 
    public DateTime End { get; set; } 

    [Required] 
    public int Price { get; set; } 
} 

Und ich habe dies auf die Standardhomecontroller (nichts Besonderes) hinzugefügt:

public ActionResult Appointment() 
    { 
     return View(new AppointmentViewModel()); 
    } 

    [HttpPost] 
    public ActionResult Appointment(AppointmentViewModel appointment) 
    { 
     return View(appointment); 
    } 

Und hier ist meine Ansicht:

<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server"> 
Appointment 
</asp:Content> 

<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server"> 
    <h2>Add Appointment</h2> 
    <%= Html.ValidationSummary() %> 
    <% using(Html.BeginForm()) { %> 
    <%= Html.EditorForModel() %> 
    <input type="submit" value="Save Changes" /> 
    <%} %> 
</asp:Content> 

Schritt 1: Einstellen der Bühne

Das erste, was Sie tun möchten, ist die "Standardvorlagen" aus dem Blog-Eintrag zu greifen. Die wichtigste in diesem Fall ist die, die in /Views/Shared/EditorTemplates/Object.asxc sitzt. Object.ascx ist der Schlüssel für die gesamte Operation. Alle Html.Editor ***** Methoden werden dies eventuell aufrufen.

nun das erste Stück der Standardfunktionalität müssen wir ändern, ist diese Linie innerhalb von Object.ascx

<% if (ViewData.TemplateInfo.TemplateDepth > 1) { %> 
    <%= ViewData.ModelMetadata.SimpleDisplayText%> 
<% } 

Was das ist, sagen ist, „nicht alle verschachtelten komplexen Typen angezeigt werden“ und wir wollen nicht, Das. Ändern Sie das> 1 in ein> 2. Nun sehen Sie Modelle in Ihrem Objektdiagramm, für die Vorlagen erstellt werden, anstatt nur Platzhaltertext zu erstellen.

Halten Sie einfach alles andere Standard für jetzt.

* Schritt 2: Übergeordnete Vorlagen **

Wenn Sie die Blog-Einträge lesen hoffentlich werden Sie jetzt verstehen, wie der Editor *** und Anzeigemethoden werden automatisch die Vorlagen in View/Shared/EditorTemplates anrufen und DisplayTemplates . Betrachten Sie sie als Aufruf von Html.RenderPartial ("TYPENAME", MyType) sie sind nicht aber es ist nah genug im Konzept.

Also, wenn Sie die Lösung so weit und gehen Sie zur richtigen URL, werden Sie feststellen, dass MVC 2 Object.ascx zweimal aufrufen wird, einmal für Ihr AppointmentViewModel und erneut für die Eigenschaft DateRange. Out of the Box rendert nur die gleiche Sammlung von Formularfeldern.

Sagen wir, wir möchten, dass unsere Vorlage unseren DateRange-Editor mit einer rot umrandeten Box umgibt. Was wir tun möchten, ist MVC 2, um eine benutzerdefinierte DateTime.ascx Vorlage anstelle von Object.ascx aufzurufen und das ist so einfach wie das Hinzufügen unserer eigenen Vorlage in View/Shared/EditorTemplates/DateRange.ascx. In diesem Fall habe ich genommen genau das, was von Object.ascx generiert wurde mit unserem Modell Daterange arbeiten und nur den Code in ein neues DateRange.ascx eingefügt:

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %> 
<div style="border: 1px solid #900"> 
    <div class="editor-label"><label for="DateRange">DateRange</label></div>    
     <div class="editor-field">    
      <div class="editor-label"><label for="DateRange_Start">Start</label> 
     </div> 


     <div class="editor-field"> 
      <input class="text-box single-line" id="DateRange_Start" name="DateRange.Start" type="text" value="" />    
     </div> 

     <div class="editor-label"><label for="DateRange_End">End</label></div> 

     <div class="editor-field"> 
      <input class="text-box single-line" id="DateRange_End" name="DateRange.End" type="text" value="" />    
     </div> 

     <div class="editor-label"><label for="DateRange_Price">Price</label></div> 

     <div class="editor-field"> 
      <input class="text-box single-line" id="DateRange_Price" name="DateRange.Price" type="text" value="" /> 

     </div>  
    </div> 
</div> 

Wala!

Jetzt, wenn Sie die Lösung ausführen, sollten Sie eine rote Box um unseren DateRange sehen. Der Rest der Anpassungen liegt bei Ihnen! Sie könnten jQuery-Datepicker-Boxen hinzufügen. In Ihrem Fall könnten Sie beide Felder in ein einzelnes Div setzen, so dass sie horizontal ausgerichtet sind. Der Himmel ist an dieser Stelle die Grenze.

Schritt 3: Validierung:

Validation ziemlich genau so funktioniert, man erwarten würde. Ein [Required] -Attribut in Ihrem DateRange-Typ funktioniert genauso wie jedes andere Validierungsattribut.

Jetzt sehen Sie, ich habe eine nicht rückwärts in der Zeit Attribut gehen kann, die ich auf dem Daterange Eigenschaft AppointmentViewModel gesetzt haben.

public class CantGoBackwardsInTime : ValidationAttribute 
{ 
    public override string FormatErrorMessage(string name) 
    { 
     return "Your date range can't go backwards in time"; 
     //return base.FormatErrorMessage(name); 
    } 

    public override bool IsValid(object value) 
    { 
     if (!(value is DateRange)) 
      throw new InvalidOperationException("This attributes can only be used on DateRange types!"); 

     var dateRange = value as DateRange; 

     return dateRange.End > dateRange.Start; 
    } 
} 

Nun, wenn Sie diese Ihre Immobilie hinzu und dekorieren Sie die Fehlermeldung in der benutzerdefinierten CantGoBackwardsInTime Validierung Attribut versehen sehen sollte: Alles, was Sie diese typspezifischen Validierungsattribute wird erben und implementieren die Basis Validation zu schaffen haben zu tun.

Ich werde aktualisieren und mehr davon löschen, wenn Sie irgendwelche Probleme haben, aber diese sollten Sie und auf dem Weg zu beginnen. (Ich dachte mir, ich könnte das vor dem Schlafengehen austesten) Nur eine Warnung: Der neue Editor für Teile von MVC 2 ist das Beste, was es auf der Welt gibt und hat ein riesiges Potential, MVC 2 Super RAD Fähigkeiten zu verleihen; Doch neben Brad Wilsons Blog gibt es kaum Informationen. Bleiben Sie einfach dabei und haben Sie keine Angst, den MVC 2-Quellcode zu sehen, wenn Sie es auch brauchen.

+0

Vielen Dank für diese jfar, ist es sicherlich gegeben ich etwas mit dem arbeiten, aber ich bin mehr das Ziel, in Richtung auf das tatsächliche Datetime-Objekt in seine Komponenten-Eingänge (über einen separaten Eingang für Jahr, Monat und Tag zum Beispiel), anstatt mehr vollständigen Datetime Aufspalten Instanzen. Denkst du, das ist immer noch der richtige Weg? Wie wäre es, wenn Sie im Rahmen dieser Lösung die clientseitige Validierung hinzufügen würden? –

+0

Nun gut. Sie müssen nur Ihre eigene DateTime-Vorlage erstellen, die die Benutzeroberfläche aufteilt. Soweit die clientseitige Validierung geht, fügen Sie einfach das Javascript in Ihre benutzerdefinierte DateTime.ascx-Vorlage ein. – jfar

+0

Ok, ich habe es mit einem der Kombinationen arbeiten war ich nach (Monat und Jahr nur in zwei getrennten Eingängen) so ein massiven vielen Dank für Ihre Hilfe und ich werde moniert dies als beantwortet. Eine Sache, über die ich mich jetzt wundere, ist, dass ein benutzerdefiniertes Validierungsattribut ein CardDate-Objekt (int month und int year) nimmt und versucht, ein gültiges Datum zu bilden. Wenn es fehlschlägt, gibt es korrekt false zurück und gibt an, dass das Kartendatum ungültig ist. Eine Sache, ist es möglich, innerhalb des Attributs beide Felder innerhalb des cardtype-Objekts ungültig zu machen, so dass sie in einem ungültigen Zustand auf der Ansicht angezeigt werden? Hoffnung, die Sinn ergab! –

0

Versuchen Sie, diese auf einer Seite zu tun? Oder eine Methode? Ich bin mir nicht sicher, wie du das machen willst, hier ist meine Aufnahme, wenn ich dich richtig verstehe.

Zum Beispiel könnten Sie so etwas für das Geburtsdatum tun.

Ihrer Ansicht

<%= Html.DropDownList("Birthday")%> 
<%= Html.DropDownList("BirthMonth")%> 
<%= Html.DropDownList("BirthYear")%> 

In Ihrem Controller haben irgendwo so etwas wie dieses. Vielleicht könntest du alles zu einer Schleife oder so kombinieren.

List<int> month = new List<int>() 
for(int i = 0; i < 12, i++) 
{ 
    month.add(i + 1); 
} 

ViewData["BirthMonth"] = new SelectList(month); 


int days = DateTime.DaysInMonth(Year, Month); 

    // do a another for loop add it to viewsData = ViewData["Birthday"] . 
    // do a another for loop for years and add it do another viewdata = ViewData["BirthYear"]. 

Also, was ich hinaus will ist Sie kann auf dem Server ein paar Sachen tun, um die Daten, die Sie wollen und fügen Sie ihn einfach durch Viewdata in die Dropdown-Listen.

+0

Hallo chobo2, danke für die Eingabe aber das geht nicht wirklich in die richtige Richtung. Ich bin auf der Suche nach einer Möglichkeit, an eine Datetime-Eigenschaft in einem Modell zu binden und trotzdem zu validieren usw. Die Verknüpfung im obigen Kommentar sollte eine bessere Vorstellung davon vermitteln, was ich zu erreichen versuche. –

Verwandte Themen