Я потратил большую часть прошедшей недели на колено в новой функциональности шаблонов, запеченной в MVC2. Мне было трудно найти шаблон DropDownList. Самая большая проблема, с которой я работал, - это получить исходные данные для выпадающего списка в шаблон. Я видел много примеров, где вы можете поместить исходные данные в словарь ViewData (ViewData ["DropDownSourceValuesKey"]), а затем получить их в самом шаблоне (var sourceValues = ViewData ["DropDownSourceValuesKey"];) Это работает, но я сделал не похоже на наличие глупой струны в качестве штыря линч для выполнения этой работы.MVC2 EditorTemplate для DropDownList
Ниже подход, который я придумал и хотел бы получить мнения по этому подходу:
вот мои цели проекта:
- модель представления должна содержать исходные данные для падения списке
- Limit Глупые Строки
- Не использовать словарь ViewData
- контроллер отвечает за заполнение свойства с исходными данными для падения вниз Список
Вот мой вид Модель:
public class CustomerViewModel
{
[ScaffoldColumn(false)]
public String CustomerCode{ get; set; }
[UIHint("DropDownList")]
[DropDownList(DropDownListTargetProperty = "CustomerCode"]
[DisplayName("Customer Code")]
public IEnumerable<SelectListItem> CustomerCodeList { get; set; }
public String FirstName { get; set; }
public String LastName { get; set; }
public String PhoneNumber { get; set; }
public String Address1 { get; set; }
public String Address2 { get; set; }
public String City { get; set; }
public String State { get; set; }
public String Zip { get; set; }
}
Мой вид Модель имеет свойство CustomerCode, которое является значением, которое пользователь выбирает из списка значений. У меня есть свойство CustomerCodeList, которое является списком возможных значений CustomerCode и является источником для выпадающего списка. Я создал атрибут DropDownList с DropDownListTargetProperty. DropDownListTargetProperty указывает на свойство, которое будет заселено на основе пользовательского выбора из сгенерированного выпадающего (в данном случае, свойства CustomerCode).
Извещение что свойство CustomerCode имеет [ScaffoldColumn (false)], заставляющее генератор пропускать поле в сгенерированном выходе.
В моем файле DropDownList.ascx будет создан элемент формы выпадающего списка с исходными данными из свойства CustomerCodeList. Сгенерированный выпадающий список будет использовать значение DropDownListTargetProperty из атрибута DropDownList в качестве атрибутов Id и Name элемента Select form. Таким образом, сгенерированный код будет выглядеть следующим образом:
<select id="CustomerCode" name="CustomerCode">
<option>...
</select>
Это работает здорово, потому что, когда форма была отправлена, MVC заполнит целевое свойство с выбранным значением из выпадающего списка, так как имя генерируемого выпадающего списка IS целевое свойство. Я представляю его как свойство CustomerCodeList как расширение своего рода свойства CustomerCode. Я связал исходные данные с этим свойством.
Вот мой код контроллера:
public ActionResult Create()
{
//retrieve CustomerCodes from a datasource of your choosing
List<CustomerCode> customerCodeList = modelService.GetCustomerCodeList();
CustomerViewModel viewModel= new CustomerViewModel();
viewModel.CustomerCodeList = customerCodeList.Select(s => new SelectListItem() { Text = s.CustomerCode, Value = s.CustomerCode, Selected = (s.CustomerCode == viewModel.CustomerCode) }).AsEnumerable();
return View(viewModel);
}
Вот мой код DropDownListAttribute:
namespace AutoForm.Attributes
{
public class DropDownListAttribute : Attribute
{
public String DropDownListTargetProperty { get; set; }
}
}
Вот мой код шаблона (DropDownList.ASCX):
<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<IEnumerable<SelectListItem>>" %>
<%@ Import Namespace="AutoForm.Attributes"%>
<script runat="server">
DropDownListAttribute GetDropDownListAttribute()
{
var dropDownListAttribute = new DropDownListAttribute();
if (ViewData.ModelMetadata.AdditionalValues.ContainsKey("DropDownListAttribute"))
{
dropDownListAttribute = (DropDownListAttribute)ViewData.ModelMetadata.AdditionalValues["DropDownListAttribute"];
}
return dropDownListAttribute;
}
</script>
<% DropDownListAttribute attribute = GetDropDownListAttribute();%>
<select id="<%= attribute.DropDownListTargetProperty %>" name="<%= attribute.DropDownListTargetProperty %>">
<% foreach(SelectListItem item in ViewData.Model)
{%>
<% if (item.Selected == true) {%>
<option value="<%= item.Value %>" selected="true"><%= item.Text %></option>
<% } %>
<% else {%>
<option value="<%= item.Value %>"><%= item.Text %></option>
<% } %>
<% } %>
</select>
Я попытался с помощью помощника Html.DropDownList, но он не позволил бы мне изменить идентификатор и имя атрибуты создаваемого элемента Select.
ПРИМЕЧАНИЕ: вам необходимо переопределить метод CreateMetadata DataAnnotationsModelMetadataProvider для DropDownListAttribute. Вот код, который:
public class MetadataProvider : DataAnnotationsModelMetadataProvider
{
protected override ModelMetadata CreateMetadata(IEnumerable<Attribute> attributes, Type containerType, Func<object> modelAccessor, Type modelType, string propertyName)
{
var metadata = base.CreateMetadata(attributes, containerType, modelAccessor, modelType, propertyName);
var additionalValues = attributes.OfType<DropDownListAttribute>().FirstOrDefault();
if (additionalValues != null)
{
metadata.AdditionalValues.Add("DropDownListAttribute", additionalValues);
}
return metadata;
}
}
Тогда вы должны сделать вызов на новый MetadataProvider в Application_Start из Global.asax.cs:
protected void Application_Start()
{
RegisterRoutes(RouteTable.Routes);
ModelMetadataProviders.Current = new MetadataProvider();
}
Ну, я надеюсь, что это имеет смысл, и я надеюсь, этот подход может сэкономить вам некоторое время. Мне хотелось бы получить отклик на этот подход. Есть ли лучший подход?
Первое, что приходит на ум, чтобы создать пользовательский шаблон редактор для ServicePackageWithOwnerName. Пользовательский шаблон ServicePackageWithOwnerName выдаст выпадающий список для свойства OwnerName. В MaintainServicePackageViewModel вы должны украсить CurrentServicePackage с помощью UIHint ("[ServicePackageWithOwnerName Tempalte Name]"). Я планирую изучить эту концепцию, но еще не успел сделать это. – tschreck
Jack- Проверьте эту ссылку, это может быть что вам нужно: http://dotnetslackers.com/articles/aspnet/asp-net-mvc-2-0-templating.aspx – tschreck
Также проверьте эту ссылку. Брэд Уилсон создал очень хорошую серию для создания шаблонов. Эта ссылка касается вложенных сложных типов. http://bradwilson.typepad.com/blog/2009/10/aspnet-mvc-2-templates-part-4-custom-object-templates.html – tschreck