Как использовать EditorForModel и DataAnnotations для сложных типов в оболочке ViewModel? - PullRequest
2 голосов
/ 06 января 2012

У меня есть 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 ]

2 голосов
/ 06 января 2012
@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 просто отобразить простой текст.

0 голосов
/ 04 июля 2014

Как показывает приведенный выше ответ, эта проблема, по-видимому, связана с каркасом, ограничивающим глубину вложения, который она будет рассматривать.

Один из способов обойти эту проблему - использовать собственный шаблон редактора. Создайте частичное представление 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.

...