ASP.NET MVC 2 Пользовательские шаблоны редактора для разделения полей даты и времени - PullRequest
8 голосов
/ 25 января 2010

На сайте, который я строю, мне нужно разбить свойства datetime на разные комбинации в зависимости от свойства. Примеры:

Представление участника имеет свойство даты рождения, которое должно отображаться в представлении как отдельные выпадающие списки день / месяц / год.

Вид кредитной карты имеет свойство даты истечения срока действия, которое должно отображаться как отдельные выпадающие списки месяц / год.

В экскурсионном представлении есть свойство только для времени, когда в качестве текстовых полей требуются отдельные часы и минуты.

Каждый из этих сценариев требует проверки и, в идеале, проверки на стороне клиента.

Я рассмотрел различные варианты, такие как настраиваемое связывание, настраиваемые атрибуты, и сейчас смотрю на настраиваемые шаблоны редактора, но пока мне не повезло в поиске подходящих решений.

Кажется, это обычная задача, но поиск в сети показал мало, что охватывает все (особенно с элементом валидации).

Итак, мой вопрос: кому-нибудь еще удалось выполнить вышеизложенное?

(скрестив пальцы!)

Ответы [ 2 ]

13 голосов
/ 26 января 2010

Ладно, я попытаюсь получить 90% пути. На самом деле это огромная и сложная часть MVC 2, и почти невозможно ответить только в этом окне ответа.

Теперь сначала вы должны зайти в блог Брэда Уилсона и подробно прочитать, как настроить шаблоны MVC 2 по умолчанию. Это должно дать вам более четкое понимание всех движущихся частей.

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

Теперь я начну с простого примера того, как создать искусственную модель представления встреч, где мы хотим убедиться, что предоставленные значения не возвращаются во времени. Не обращайте внимания на атрибуты прямо сейчас, мы туда доберемся.

Вот модель представления, которую я использую:

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

И я добавил это к стандартному HomeController (ничего особенного):

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

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

А вот мой взгляд:

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

Шаг 1: настройка сцены

Первое, что вы хотите сделать, это взять «шаблоны по умолчанию» из записи в блоге. Важным в этом случае является тот, который будет находиться в /Views/Shared/EditorTemplates/Object.asxc Object.ascx - это краеугольный камень всей операции. Все методы Html.Editor ***** будут вызывать это в конечном итоге.

Теперь первой частью функциональности по умолчанию, которую мы должны изменить, является эта строка внутри Object.ascx

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

То, что говорится: «не отображать вложенные сложные типы», и мы этого не хотим. Измените это> 1 на a> 2. Теперь для просмотра моделей на вашем графе объектов будут созданы шаблоны для них, а не просто текст-заполнитель.

Просто оставьте пока все остальное по умолчанию.

* Шаг 2. Переопределение шаблонов **

Если вы прочитаете записи блога, надеюсь, теперь вы поймете, как методы Editor *** и Display будут автоматически вызывать шаблоны в View / Shared / EditorTemplates и DisplayTemplates. Думайте о них как о вызове Html.RenderPartial («TYPENAME», MyType), но они не достаточно близки по своей концепции.

Так что, если вы запустите решение до этого и перейдете к правильному URL, вы заметите, что MVC 2 будет вызывать Object.ascx дважды, один раз для вашего AppointmentViewModel и снова для свойства DateRange. Из коробки просто визуализируется та же коллекция полей формы.

Допустим, мы хотим, чтобы наш шаблон окружил наш редактор DateRange красной рамкой. Мы хотим, чтобы MVC 2 с коротким замыканием вызывал пользовательский шаблон DateTime.ascx вместо Object.ascx, и это так же просто, как добавить наш собственный шаблон в View / Shared / EditorTemplates / DateRange.ascx. В этом случае я просто взял то, что было сгенерировано Object.ascx, работающим с нашей моделью DateRange, и просто вставил код в новый 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>

Вал!

Теперь, когда вы запускаете решение, вы должны увидеть красное поле вокруг нашего DateRange. Остальные настройки зависят от вас! Вы можете добавить jQuery коробки выбора даты. В вашем случае вы можете поместить оба поля в один элемент div, чтобы они располагались горизонтально. Небо это предел в этой точке.

Шаг 3: Проверка:

Валидация работает практически так, как вы ожидаете. Атрибут [Обязательный] внутри вашего Тип DateRange работает так же, как и любой другой атрибут проверки.

Теперь вы видите, что я создал атрибут «не могу вернуться назад во времени», который я наложил на свойство DateRange в AppointmentViewModel. Все, что вам нужно сделать, чтобы создать эти специфичные для типа атрибуты проверки, это наследовать и реализовать базовый атрибут ValidationAttribute:

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

Теперь, если вы добавите это и украсите свое свойство, вы увидите сообщение об ошибке, предоставленное в пользовательском атрибуте проверки CantGoBackwardsInTime.

Я обновлю и уточню больше, если у вас есть какие-либо проблемы, но это должно помочь вам начать работу. (подумал, что я мог бы сделать это перед сном) Просто предупреждение: новый редактор для кусочков MVC 2 - самая удивительная вещь в мире и обладает огромным потенциалом, чтобы дать MVC 2 супер RAD-возможности; Тем не менее, кроме блога Брэда Уилсона, мало что можно узнать. Просто продолжайте и не бойтесь заглянуть в исходный код MVC 2, если вам это тоже нужно.

0 голосов
/ 26 января 2010

Вы пытаетесь сделать все это на одной странице? Или один метод? Я не совсем уверен, как вы хотите это сделать, поэтому вот мой выстрел, если я вас правильно понимаю.

Так, например, вы можете сделать что-то подобное для даты рождения.

На ваш взгляд

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

В вашем контроллере где-то есть что-то подобное. Может быть, вы могли бы объединить все это в один цикл или что-то в этом роде.

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

Итак, вы можете сделать что-то на сервере, чтобы получить нужные вам даты и просто добавить их через ViewData в выпадающие списки.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...