可以将一个模型通过多个编辑模板通过? [英] Can one model be passed through multiple editor templates?

查看:92
本文介绍了可以将一个模型通过多个编辑模板通过?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想使用的包装在一个字段模型应用的基础对象编辑模板之前编辑模板,显示视图模型。

我的观点:

  @model Mvc3VanillaApplication.Models.ContactModel@using(Html.BeginForm())
{
    @ Html.EditorForModel(字段集)
}


使用字段集模板(查看/共享/ EditorTemplates / Fieldset.cshtml):

 <&字段集GT;
    <传奇> @ ViewData.ModelMetadata.DisplayName< /传说>
    @ Html.EditorForModel()
< /字段集>


又使用一个基本的模板为所有对象(查看/共享/ EditorTemplates / Object.cshtml):

  @foreach(在ViewData.ModelMetadata.Properties.Where VAR道具(X =>
    x.ShowForEdit&功放;&安培; !x.IsComplexType&放大器;&安培; !ViewData.TemplateInfo.Visited(X)))
{
    @ Html.Label(prop.PropertyName,prop.DisplayName)
    @ Html.Editor(prop.PropertyName)
}


这是我的意图呢。的问题是,虽然在网页与一个字段和一个说明呈现,对象模板不施加所以不显示任何输入控件。

如果我更改视图不指定字段集模板,然后我的模型的属性是使用对象模板来渲染,所以它不是我的模板对象无法找到。

是否有可能通过多种模板,通过同型号?

有关它的价值,视图模型是这样的:

 命名空间Mvc3VanillaApplication.Models
{
    [System.ComponentModel.DisplayName(联系方式)]
    公共类ContactModel
    {
        公共字符串名字{获得;组; }
        公共字符串名字{获得;组; }
    }
}


解决方案

我实现你所拥有的,并能重现它。我设置 Object.cshtml 一个破发点,所以我可以检查它,我被猝不及防地认识到,它甚至没有被击中的对象模板时字段集模板正在使用。然后,我通过字段集模板阶梯,只见它被调用模板就好了,这样的东西必须在code这prevents从显示对象模板发生。

我打开了 MVC3源$ C ​​$ C ,搜索 EditorForModel 键,找到了正确的功能。

 公共静态MvcHtmlString EditorForModel(这个HTML的HtmlHelper){
    返回MvcHtmlString.Create(TemplateHelpers.TemplateHelper(HTML,html.ViewData.ModelMetadata,的String.Empty,NULL / * * TEMPLATENAME /,DataBoundControlMode.Edit,空/ * * additionalViewData /));
}

显然,这是不是,所以我pressed F12上的 TemplateHelpers.TemplateHelper ,一旦有一次我pressed F12 上单线电话,为您带来给函数的肉。在这里,我找到了code的这种短位开始对214行 TemplateHelpers.cs

  //通常这不应该发生,除非有人写自己的定制对象模板,
//不检查,以确保该对象尚未显示
反对visitedObjectsKey = metadata.Model? metadata.RealModelType;
如果(html.ViewDataContainer.ViewData.TemplateInfo.VisitedObjects.Contains(visitedObjectsKey)){// DDB#224750
    返回的String.Empty;
}

这些评论实际上是在code,在这里我们有回答你的问题:可以在一个模型可以通过多个编辑模板通过,答案是否*?

话虽这么说,这似乎是一个非常合理的用例这样的功能,所以找到一个替代可能是值得的。我怀疑一个模板剃刀代表将解决这个包装的功能,所以我尝试过了。

  @ {
    FUNC&LT;动态,对象&gt;字段集= @<fieldset><legend>@ViewData.ModelMetadata.DisplayName</legend>@Html.EditorForModel()</fieldset>;
}@using(Html.BeginForm())
{
    //@Html.EditorForModel(\"Fieldset)
    // @ Html.EditorForModel()
    @fieldset(型号)
}

和中提琴!有效!我会让你来实现这个作为扩展(和更多的可重复使用的)方法。下面是一个简短的博客文章了解模板剃刀代表


*从技术上讲,你可以重写这个函数和编译自己的MVC3版本,但它可能是更多的麻烦比它的价值。我们试图做到这一点在事业项目时,我们发现了 Html.ActionLink 功能是相当缓慢的,当你有定义几百路线。有与我们决定是不值得我们的时间,通过现在的工作和维护MVC的未来版本库的其余部分签约的问题。

I'm trying to display a view model using an editor template that wraps the model in a fieldset before applying a base Object editor template.

My view:

@model Mvc3VanillaApplication.Models.ContactModel

@using (Html.BeginForm())
{
    @Html.EditorForModel("Fieldset")
}


Uses a fieldset template (Views/Shared/EditorTemplates/Fieldset.cshtml):

<fieldset>
    <legend>@ViewData.ModelMetadata.DisplayName</legend>
    @Html.EditorForModel()
</fieldset>


Which in turn uses a basic template for all objects (Views/Shared/EditorTemplates/Object.cshtml):

@foreach (var prop in ViewData.ModelMetadata.Properties.Where(x => 
    x.ShowForEdit && !x.IsComplexType && !ViewData.TemplateInfo.Visited(x)))
{
    @Html.Label(prop.PropertyName, prop.DisplayName)
    @Html.Editor(prop.PropertyName)
}


That's my intent anyway. The problem is that while the page renders with a fieldset and a legend, the Object template isn't applied so no input controls are displayed.

If I change the view to not specify the "Fieldset" template then my model's properties are rendered using the Object template, so it's not that my Object template can't be found.

Is it possible to pass the same model through multiple templates?

For what it's worth, the view model looks like this:

namespace Mvc3VanillaApplication.Models
{
    [System.ComponentModel.DisplayName("Contact Info")]
    public class ContactModel
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }
    }
}

解决方案

I implemented what you have, and was able to reproduce it. I set a break point in Object.cshtml so I could inspect it and I was caught off guard to realize that it wasn't even hitting the object template when the fieldset template was being used. Then I stepped through the fieldset template and saw it was calling the template just fine, so something must be happening in the code which prevents it from displaying the object template.

I opened up the MVC3 source code, searched for EditorForModel and found the correct function.

public static MvcHtmlString EditorForModel(this HtmlHelper html) {
    return MvcHtmlString.Create(TemplateHelpers.TemplateHelper(html, html.ViewData.ModelMetadata, String.Empty, null /* templateName */, DataBoundControlMode.Edit, null /* additionalViewData */));
}

Obviously this wasn't it, so I pressed F12 on TemplateHelpers.TemplateHelper, and once there again I pressed F12 on single line call which brings you to the meat of the function. Here I found this short bit of code starting on line 214 of TemplateHelpers.cs:

// Normally this shouldn't happen, unless someone writes their own custom Object templates which
// don't check to make sure that the object hasn't already been displayed
object visitedObjectsKey = metadata.Model ?? metadata.RealModelType;
if (html.ViewDataContainer.ViewData.TemplateInfo.VisitedObjects.Contains(visitedObjectsKey)) {    // DDB #224750
    return String.Empty;
}

Those comments are actually in the code, and here we have the answer to your question: Can one model be passed through multiple editor templates?, the answer is no*.

That being said, this seems like a very reasonable use case for such a feature, so finding an alternative is probably worth the effort. I suspected a templated razor delegate would solve this wrapping functionality, so I tried it out.

@{
    Func<dynamic, object> fieldset = @<fieldset><legend>@ViewData.ModelMetadata.DisplayName</legend>@Html.EditorForModel()</fieldset>;
}

@using (Html.BeginForm())
{
    //@Html.EditorForModel("Fieldset")
    //@Html.EditorForModel()
    @fieldset(Model)
}

And viola! It worked! I'll leave it up to you to implement this as an extension (and much more reusable) method. Here is a short blog post about templated razor delegates.


* Technically you could rewrite this function and compile your own version of MVC3, but it's probably more trouble than it's worth. We tried to do this on the careers project when we found out that the Html.ActionLink function is quite slow when you have a few hundred routes defined. There is a signing issue with the rest of the libraries which we decided was not worth our time to work through now and maintain for future releases of MVC.

这篇关于可以将一个模型通过多个编辑模板通过?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆