Как использовать EditorForModel и DataAnnotations для сложных типов в оболочке ViewModel?
У меня есть ViewModel, оборачивающий два сложных типа:
public class EditProductViewModel
{
public ProductData ProductData { get; set; }
public FridgeContent FridgeContent { get; set; }
}
и это мнение:
@model EditProductViewModel
@using (Html.BeginForm("Edit", "ProductData", FormMethod.Post))
{
@Html.EditorForModel()
[...]
}
ProductData и FridgeContent содержат свойства POCO с аннотациями Data:
public class FridgeContentMetadata : DatabaseEntityMetadataBase
{
[Required]
[HiddenInput(DisplayValue = false)]
public int ProductDataId { get; set; }
[Required]
[UIHint("StringReadOnly")]
public int ScaleId { get; set; }
[Required]
[UIHint("StringReadOnly")]
[Range(0.01, float.MaxValue, ErrorMessage = "The weight of a product must be positive.")]
public float Weight { get; set; }
[...]
}
Я хочу отредактировать и ProductData, и FridgeContent в EditProductView, используя соответствующие аннотации данных из этих классов и метод EditorForModel() (я не хочу создавать шаблоны самостоятельно). Поэтому я создал шаблоны ProductData.cshtml и FridgeContent.cshtml в /Views/Shared/EditorTemplates/:
@model FridgeContent
@Html.EditorForModel()
К сожалению, представление для EditProductViewModel пустое (ошибок не возникает). Если я использую EditorForModel только для FridgeContent или ProductData, он работает нормально. Я также попытался добавить аннотации [UIHInt("..")] в EditProductViewModel, но это не имеет значения.
Что мне не хватает?
2 ответа
@model EditProductViewModel
@using (Html.BeginForm("Edit", "ProductData", FormMethod.Post))
{
@Html.EditorFor(o=> o.ProductData )
@Html.EditorFor(o=> o.FridgeContent )
}
или создайте для вас шаблон редактирования ViewModel, содержащий эти две строки
@Html.EditorFor(o=> o.ProductData )
@Html.EditorFor(o=> o.FridgeContent )
UPADTE:
Ну, наконец-то, потому что движок рендеринга не займёт больше одного шага в иерархии объектов, вы также можете найти его в коде asp.net mvc.
Проверьте исходный код MVC 3.0 здесь:
Есть файл с именем DefaultEditorTemplates.cs
который содержит этот метод:
internal static string ObjectTemplate(HtmlHelper html, TemplateHelpers.TemplateHelperDelegate templateHelper) {
ViewDataDictionary viewData = html.ViewContext.ViewData;
TemplateInfo templateInfo = viewData.TemplateInfo;
ModelMetadata modelMetadata = viewData.ModelMetadata;
StringBuilder builder = new StringBuilder();
if (templateInfo.TemplateDepth > 1) { // DDB #224751
return modelMetadata.Model == null ? modelMetadata.NullDisplayText : modelMetadata.SimpleDisplayText;
}
foreach (ModelMetadata propertyMetadata in modelMetadata.Properties.Where(pm => ShouldShow(pm, templateInfo))) {
if (!propertyMetadata.HideSurroundingHtml) {
string label = LabelExtensions.LabelHelper(html, propertyMetadata, propertyMetadata.PropertyName).ToHtmlString();
if (!String.IsNullOrEmpty(label)) {
builder.AppendFormat(CultureInfo.InvariantCulture, "<div class=\"editor-label\">{0}</div>\r\n", label);
}
builder.Append("<div class=\"editor-field\">");
}
builder.Append(templateHelper(html, propertyMetadata, propertyMetadata.PropertyName, null /* templateName */, DataBoundControlMode.Edit, null /* additionalViewData */));
if (!propertyMetadata.HideSurroundingHtml) {
builder.Append(" ");
builder.Append(html.ValidationMessage(propertyMetadata.PropertyName));
builder.Append("</div>\r\n");
}
}
return builder.ToString();
}
в котором четко говорится, что если TemplateDepth > 1
просто сделать простой текст.
Как показывает приведенный выше ответ, эта проблема, по-видимому, связана с каркасом, ограничивающим глубину вложенности, которую он будет рассматривать.
Один из способов обойти эту проблему - использовать собственный шаблон редактора. Создать частичное представление, Object.cshtml
, в Views/Shared/EditorTemplates
, Вот пример шаблона, взятый отсюда:
@{
Func<ModelMetadata, bool> ShouldShow = metadata =>
metadata.ShowForEdit && !ViewData.TemplateInfo.Visited(metadata);
}
@if (ViewData.TemplateInfo.TemplateDepth > 5) {
if (Model == null) {
@ViewData.ModelMetadata.NullDisplayText
} else {
@ViewData.ModelMetadata.SimpleDisplayText
}
} else {
foreach (var prop in ViewData.ModelMetadata.Properties.Where(ShouldShow)) {
if (prop.HideSurroundingHtml) {
@Html.Editor(prop.PropertyName)
} else {
if (string.IsNullOrEmpty(Html.Label(prop.PropertyName).ToHtmlString())==false) {
<div class="editor-label">
@Html.Label(prop.PropertyName)
</div>
}
<div class="editor-field">
@Html.Editor(prop.PropertyName)
@Html.ValidationMessage(prop.PropertyName)
</div>
}
}
}
В приведенном выше примере вы можете установить максимальную глубину вложения, изменив 5
постоянная.