【问题标题】:How to use EditorForModel and DataAnnotations for complex types in a wrapping ViewModel?如何在包装 ViewModel 中为复杂类型使用 EditorForModel 和 DataAnnotations?
【发布时间】:2012-01-06 12:08:22
【问题描述】:

我有一个封装了两种复杂类型的 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 包含带有 DataAnnotations 的 POCO 属性,如下所示:

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

    [...]
}

我想使用来自这些类的适当数据注释和 EditorForModel() 方法在 EditProductView 中编辑 ProductData 和 FridgeContent(我不想自己生成模板)。因此,我在 /Views/Shared/EditorTemplates/ 中创建了模板 ProductData.cshtml 和 FridgeContent.cshtml:

@model FridgeContent 
@Html.EditorForModel()

很遗憾,EditProductViewModel 的视图是空的(没有引发错误)。如果我将 EditorForModel 单独用于 FridgeContent 或 ProductData,它工作正常。我还尝试向 EditProductViewModel 添加 [UIHInt("..")] 注释,但这并没有什么不同。

我错过了什么?

【问题讨论】:

    标签: asp.net-mvc-3 viewmodel data-annotations editorformodel


    【解决方案1】:
    @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 )
    

    更新:

    哦,终于明白了,因为渲染引擎在对象层次结构中不会走多一步,你也可以在 asp.net mvc 代码中找到它。

    查看 MVC 3.0 源代码Here

    有一个名为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 &gt; 1 只是呈现一个简单的文本。

    【讨论】:

    • 如果我只是在 ProductData 或 FridgeContent 的 EditorTemplate 中放置一个字符串,它可以工作,但使用 EditorForModel() 不能。
    • 如果你想使用EditorForModel你必须创建一个编辑模板,我已经添加了这部分来回答。
    • 不,我的意思是我不能在 EditorTemplate 中为 ProductData 或 FridgeContent 使用 EditorForModel()。我将您的代码添加到 EditProductViewModel 视图中,这可以正常工作,但前提是调用的 EditorTemplates 包含简单字符串而不是 EditorForModel()。
    • 因为在 EditProductViewModel 视图后面有一个 Model 属性
    • 那是因为[UIHint("StringReadOnly")]这个注解在ScaleId属性之上
    【解决方案2】:

    正如上面的答案所示,这个问题似乎与框架限制了它所考虑的嵌套深度有关。

    解决此问题的一种方法是使用您自己的编辑器模板。在Views/Shared/EditorTemplates 中创建局部视图Object.cshtml。这是取自here的示例模板:

    @{
        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 常量来设置最大嵌套深度。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-06-16
      • 2014-09-02
      • 1970-01-01
      • 2012-07-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多