2010-01-25 19 views
8

W witrynie, którą buduję, muszę mieć właściwości datetime podzielone na różne kombinacje w zależności od właściwości. Przykłady:ASP.NET MVC 2 Niestandardowe szablony edytora do dzielenia datetime pól

Widok członka ma datę urodzenia, którą należy pokazać w widoku jako oddzielne listy dni/miesięcy/roku.

Widok karty kredytowej ma właściwość daty ważności, która musi być wyświetlana jako oddzielne listy miesiąc/rok.

Widok wycieczki ma właściwość tylko w czasie, w której oddzielne godziny i minuty są potrzebne jako pola tekstowe.

Każdy z tych scenariuszy wymaga sprawdzania poprawności, a także sprawdzania poprawności po stronie klienta.

Przyjrzałem się różnym opcjom, takim jak niestandardowe powiązanie, niestandardowe atrybuty i teraz szukam niestandardowych szablonów edytora, ale do tej pory nie miałem szczęścia w znalezieniu odpowiednich rozwiązań.

Wydaje się, że to typowe zadanie, ale przeszukiwanie sieci pokazało niewiele, co obejmuje wszystko (szczególnie z elementem sprawdzania poprawności).

Moje pytanie brzmi, czy ktoś inny zdołał osiągnąć powyższe?

(kciuki!)

+0

"ale do tej pory nie miałem szczęścia w znalezieniu odpowiednich rozwiązań." Co to oznacza? – jfar

+0

Witam jfar, jestem całkiem nowy dla C# i mvc i dlatego polegam na wyszukiwaniach google, aby znaleźć dobry punkt wyjścia dla rozwiązania. Głównym z nich był http://www.hanselman.com/blog/SplittingDateTimeUnitTestingASPNETMVCCustomModelBinders.aspx, ale nie mogłem wymyślić, jak dodać sprawdzanie poprawności (po stronie serwera lub po stronie klienta). –

+0

No dobra, myślałem, że to coś innego. Chyba że ktoś inny odpowie, dziś wieczorem dam odpowiedź. Robię tego typu rzeczy przez cały czas. – jfar

Odpowiedz

13

Ok, spróbuję dostać 90% drogi. Jest to w rzeczywistości ogromna i złożona część MVC 2 i prawie niemożliwe do udzielenia odpowiedzi tylko w tym polu odpowiedzi.

Teraz należy najpierw odwiedzić bloga Brada Wilsona i dokładnie przeczytać, jak dostosować domyślne szablony MVC 2. To powinno dać ci dużo lepsze zrozumienie wszystkich ruchomych części.

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

Teraz zacznę prosty przykład jak stworzyć contrived termin widok model, w którym chcemy się upewnić wartości dostarczonych nie cofnąć się w czasie. Nie zwracaj uwagi na atrybuty już teraz, dotrzemy tam.

Oto ViewModel Używam:

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; } 
} 

I dodałem to do domyślnej HomeController (nic nadzwyczajnego):

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

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

I tu jest moim zdaniem:

<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> 

Krok 1: Ustawienie stołu montażowego

Pierwszą rzeczą, którą chcesz zrobić, to pobrać "domyślne szablony" z wpisu blogu. Ważnym w tym przypadku jest ten, który będzie siedział w /Views/Shared/EditorTemplates/Object.asxc Object.ascx jest kamieniem węgielnym dla całej operacji. Wszystkie metody Html.Editor ***** wywołają to w końcu.

Teraz pierwszy kawałek domyślnej funkcjonalności musimy zmienić to ta linia wewnątrz Object.ascx

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

Co to jest to powiedzieć, „nie wyświetla żadnych zagnieżdżone typy złożone”, a nie chcemy że. Zmień> 1 na a> 2. Teraz modele widoków na wykresie obiektów będą miały dla nich szablony zamiast tylko tworzyć tekst zastępczy.

Po prostu pozostaw wszystko inne domyślne na teraz.

* Krok 2: Zastępowanie Szablony **

Jeśli czytasz wpisy z nadzieją zrozumiesz teraz, w jaki sposób Edytor *** i metody wyświetlania automatycznie zadzwoni szablony w widoku/Shared/EditorTemplates i DisplayTemplates . Pomyśl o nich jako o nazwie Html.RenderPartial ("TYPENAME", MyType), ale nie są one wystarczająco bliskie w koncepcji.

Jeśli więc uruchomisz rozwiązanie tak daleko i przejdziesz do poprawnego adresu URL, zauważysz, że MVC 2 wywoła obiekt Object.ascx dwa razy, raz dla twojego AppointmentViewModel i ponownie dla właściwości DateRange. Po wyjęciu z pudełka jest renderowany ten sam zbiór pól formularza.

Powiedzmy, że chcemy, aby nasz szablon otaczał nasz edytor DateRange czerwonym obramowaniem. Chcemy krótko przerwać MVC 2, aby wywołać niestandardowy szablon DateTime.ascx zamiast Object.ascx i to jest tak proste, jak dodanie naszego własnego szablonu w widoku/Shared/EditorTemplates/DateRange.ascx. W tym przypadku Właśnie podjęte co zostało wygenerowane przez Object.ascx pracy z naszym modelu DATERANGE i właśnie wklejony kod do nowego DateRange.ascx:

<%@ 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!

Teraz po uruchomieniu rozwiązania powinno pojawić się czerwone pole wokół naszego DataRange. Reszta dostosowań zależy od Ciebie! Można dodać pola datepicker jQuery. W twoim przypadku możesz umieścić oba pola w jednym dziale, aby były wyrównane poziomo. Niebo jest w tym momencie granicą.

Krok 3: Walidacja:

Validation działa prawie tak, jak można oczekiwać. Atrybut [Wymagany] w danym typie DateRange działa tak samo, jak każdy inny atrybut sprawdzania poprawności.

Teraz widzisz, że zrobiłem nie mogę cofnąć w czasie atrybut, który umieściłem na właściwości DateRange z AppointmentViewModel. Wszystko co musisz zrobić, aby stworzyć tego typu atrybuty specyficzne walidacja jest dziedziczyć i wdrożenie ValidationAttribute bazowy:

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; 
    } 
} 

Teraz, jeśli dodać to i ozdobić swoje właściwości powinien pojawić się komunikat błędu z atrybutem walidacji zwyczaj CantGoBackwardsInTime.

Będę aktualizować i usuwać więcej tego, jeśli masz jakiekolwiek problemy, ale to powinno Ci zacząć i po drodze. (myślałem, że uda mi się to zignorować przed snem) Tylko ostrzeżenie: nowy edytor kawałków MVC 2 jest najbardziej niesamowitą rzeczą na świecie i ma ogromny potencjał, aby nadać MVC 2 super RAD; ale oprócz bloga Brada Wilsona jest niewiele informacji. Po prostu trzymaj się tego i nie bój się podglądać kodu źródłowego MVC 2, jeśli potrzebujesz.

+0

Dziękuję za to jfar, to z pewnością dało mi coś do pracy, ale bardziej zmierzam do podziału rzeczywistego obiektu datetime na jego komponenty wejściowe (oddzielny wkład na rok, miesiąc i dzień na przykład) zamiast wielu pełnych datetime instancje. Czy uważasz, że to nadal jest właściwa droga? Co powiesz na temat dodawania walidacji po stronie klienta w ramach tego rozwiązania? –

+0

No dobrze. Musisz tylko utworzyć własny szablon DateTime, który podzieli interfejs użytkownika. Jeśli chodzi o walidację po stronie klienta, po prostu włącz javascript w niestandardowym szablonie DateTime.ascx. – jfar

+0

Ok, mam to działa z jedną z kombinacji, których byłem (miesiąc i rok tylko w dwóch oddzielnych danych wejściowych), więc ogromnie dziękuję za pomoc i zaznaczę to jako odpowiedź. Jedną rzeczą, którą się teraz zastanawiam jest to, że niestandardowy atrybut sprawdzania poprawności przyjmuje obiekt CardDate (int miesiąc i rok int) i próbuje utworzyć poprawną datę. jeśli się nie powiedzie, poprawnie zwróci fałszywe stwierdzenie, że data ważności karty jest nieprawidłowa. Jedną z rzeczy jest to, czy z atrybutu można uczynić oba pola w obiekcie typu inwalida nieważnymi, aby były wyświetlane w nieprawidłowym stanie w widoku? Mam nadzieję, że to ma sens! –

0

Czy próbujesz zrobić to wszystko na jednej stronie? Lub jednej metody? Nie jestem pewien, jak chcesz to zrobić, więc tutaj jest mój strzał, jeśli dobrze cię zrozumiem.

Na przykład można zrobić coś takiego dla daty urodzin.

W widoku

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

W kontrolerze gdzieś coś takiego. Może mógłbyś połączyć to wszystko w jedną pętlę lub coś w tym stylu.

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"]. 

Więc co ja dostaję na to twój może zrobić kilka rzeczy na serwerze, aby uzyskać daty, które chcesz i dodaj go poprzez ViewData w rozwijanych list.

+0

Cześć, chobo2, dziękuję za wejście, ale to naprawdę nie idzie w dobrym kierunku. Szukam sposobu na powiązanie z właściwością datetime w modelu i nadal sprawdzam poprawność, itp. Link w powyższym komentarzu powinien dać lepsze wyobrażenie o tym, co próbuję osiągnąć. –

Powiązane problemy