Строили, строили, и наконец построили. Новый проект, который должен будет кормить фирму следующие N лет, дорос до беты.

image

Отдам ключи от беты в хорошие руки :)

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

Для того, чтобы стандартная клиентская валидация заработала, нужно сделать следующее:

  1. Заполнить метаданные. Мы сделали это в прошлой части.
  2. Заполнить поля ViewData.TemplateInfo. В нашем случае – из TemplateInfo родительского действия.
  3. Отрендерить выпадающий список на основе метаданных и данных шаблона.

Изменения затронут только представление выпадающего списка.

ViewsListDropDown.cshtml

@model SelectList
@{
   
this
.ViewContext.ViewData.TemplateInfo.FormattedModelValue
        =
this
.ViewContext.ParentActionViewContext.ViewData.TemplateInfo.FormattedModelValue;
       
   
this
.ViewContext.ViewData.TemplateInfo.HtmlFieldPrefix
        =
this
.ViewContext.ParentActionViewContext.ViewData.TemplateInfo.HtmlFieldPrefix;
}
@
Html.DropDownList(
   
""
,
   
this
.Model,
   
this.ViewData.ModelMetadata.NullDisplayText
    )

Важно: ни в коем случае нельзя подменять ссылку ViewData.TemplateInfo на объект из родительского контекста. ASP.NET MVC рендерит атрибуты валидации только для первого элемента управления с заданным именем. В нашем примере это приведет к отсутствию валидаторов у всех списков, кроме первого.

После этого валидаторы заработают, и даже слишком хорошо:

image

В стандартном валидаторе целочисленного формата есть баг – он учитывает только атрибут value у элементов списка, и не учитывает innerText. Т.е. выбранный на картинке выше <option>1992</option> он числом не считает.

Для обхода этого бага можно создать SelectList с явным указанием имен свойств для Text/Value:

ControllersListController.cs

public ActionResult Years()
{
   
int? selectedYear = this.ControllerContext.ParentActionViewContext.ViewData.Model as int
?;

   
var model = new SelectList(Enumerable.Range(1990, 20).Select(y => new
{ Value = y }),
       
"Value", "Value"
, selectedYear);

   
this
.ViewData.Model = model;
   
this.ViewData.ModelMetadata = this
.ControllerContext.ParentActionViewContext.ViewData.ModelMetadata;

   
return View("DropDown");
}

Некрасиво, но работает. Надеюсь, баг исправят в релизе :)

Исходный код к этой статье: MvcDropDowns2.zip. Требует ASP.NET MVC 3.0 RC2 для запуска.

Наткнулся на забавный глюк – студия стала намертво подвисать при попытке открытия web.config rewrite-файла. После перезапуска файл открывался вполне нормально, но через некоторое время зависон повторяется. Убивание suo/user не помогло.

Поковырял ее отладчиком, и выяснил что висит она на SqlConnection.Open. Непонятно зачем, но при открытии реврайта студия пытается подсоединиться ко всем серверам, зарегистрированным в Server Explorer/Data Connection. Почистил оттуда мертвые записи – подвисания прошли.