ASP.NET MVC部分视图:input名称前缀
假设我有ViewModel
public class AnotherViewModel { public string Name { get; set; } } public class MyViewModel { public string Name { get; set; } public AnotherViewModel Child { get; set; } public AnotherViewModel Child2 { get; set; } }
在我看来,我可以渲染一个部分
<% Html.RenderPartial("AnotherViewModelControl", Model.Child) %>
在部分我会做的
<%= Html.TextBox("Name", Model.Name) %> or <%= Html.TextBoxFor(x => x.Name) %>
然而,问题是这两个将呈现name =“名称”,而我需要有名称=“Child.Name”为了使模型联编程序正常工作。 或者,当我使用相同的局部视图呈现第二个属性时,name =“Child2.Name”。
如何让我的部分视图自动识别所需的前缀? 我可以通过它作为参数,但这太不方便了。 当我想例如recursion地呈现它时,情况更糟。 有没有办法使用前缀来渲染部分视图,或者更好的方法是自动重新调用lambdaexpression式
<% Html.RenderPartial("AnotherViewModelControl", Model.Child) %>
会自动添加正确的“孩子”。 生成的名称/ IDstring的前缀?
我可以接受任何解决scheme,包括第三方视图引擎和库 – 我实际上使用Spark View Engine(我使用它的macros“解决”问题)和MvcContrib,但没有find解决scheme。 XForms,InputBuilder,MVC v2 – 提供这种function的任何工具/洞察都将非常棒。
现在我想自己编码,但是好像浪费时间,我不敢相信这个小东西已经不能实现了。
很多手动解决scheme可能存在,并且都是受欢迎的。 例如,我可以强制我的partials基于IPartialViewModel <T> {公共string前缀; T型号; }。 但是我宁愿select一些现有的/认可的解决scheme。
更新:这里有一个类似的问题没有答案。
您可以通过以下方式扩展Html助手类:
using System.Web.Mvc.Html public static MvcHtmlString PartialFor<TModel, TProperty>(this HtmlHelper<TModel> helper, System.Linq.Expressions.Expression<Func<TModel, TProperty>> expression, string partialViewName) { string name = ExpressionHelper.GetExpressionText(expression); object model = ModelMetadata.FromLambdaExpression(expression, helper.ViewData).Model; var viewData = new ViewDataDictionary(helper.ViewData) { TemplateInfo = new System.Web.Mvc.TemplateInfo { HtmlFieldPrefix = name } }; return helper.Partial(partialViewName, model, viewData); }
只需在您的意见中使用它:
<%= Html.PartialFor(model => model.Child, "_AnotherViewModelControl") %>
你会看到一切都好!
到目前为止,我正在寻找同样的东西,我发现这个最近的post:
http://davybrion.com/blog/2011/01/prefixing-input-elements-of-partial-views-with-asp-net-mvc/
<% Html.RenderPartial("AnotherViewModelControl", Model.Child, new ViewDataDictionary { TemplateInfo = new System.Web.Mvc.TemplateInfo { HtmlFieldPrefix = "Child1" } }) %>
使用MVC2你可以做到这一点。
这里是强types的视图:
<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<MvcLearner.Models.Person>" %> <asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server"> Create </asp:Content> <asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server"> <h2>Create</h2> <% using (Html.BeginForm()) { %> <%= Html.LabelFor(person => person.Name) %><br /> <%= Html.EditorFor(person => person.Name) %><br /> <%= Html.LabelFor(person => person.Age) %><br /> <%= Html.EditorFor(person => person.Age) %><br /> <% foreach (String FavoriteFoods in Model.FavoriteFoods) { %> <%= Html.LabelFor(food => FavoriteFoods) %><br /> <%= Html.EditorFor(food => FavoriteFoods)%><br /> <% } %> <%= Html.EditorFor(person => person.Birthday, "TwoPart") %> <input type="submit" value="Submit" /> <% } %> </asp:Content>
以下是子类的强types视图(必须存储在视图目录的子文件夹EditorTemplates中):
<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<MvcLearner.Models.TwoPart>" %> <%= Html.LabelFor(birthday => birthday.Day) %><br /> <%= Html.EditorFor(birthday => birthday.Day) %><br /> <%= Html.LabelFor(birthday => birthday.Month) %><br /> <%= Html.EditorFor(birthday => birthday.Month) %><br />
这里是控制器:
public class PersonController : Controller { // // GET: /Person/ [AcceptVerbs(HttpVerbs.Get)] public ActionResult Index() { return View(); } [AcceptVerbs(HttpVerbs.Get)] public ActionResult Create() { Person person = new Person(); person.FavoriteFoods.Add("Sushi"); return View(person); } [AcceptVerbs(HttpVerbs.Post)] public ActionResult Create(Person person) { return View(person); } }
这里是自定义类:
public class Person { public String Name { get; set; } public Int32 Age { get; set; } public List<String> FavoriteFoods { get; set; } public TwoPart Birthday { get; set; } public Person() { this.FavoriteFoods = new List<String>(); this.Birthday = new TwoPart(); } } public class TwoPart { public Int32 Day { get; set; } public Int32 Month { get; set; } }
和输出源:
<form action="/Person/Create" method="post"><label for="Name">Name</label><br /> <input class="text-box single-line" id="Name" name="Name" type="text" value="" /><br /> <label for="Age">Age</label><br /> <input class="text-box single-line" id="Age" name="Age" type="text" value="0" /><br /> <label for="FavoriteFoods">FavoriteFoods</label><br /> <input class="text-box single-line" id="FavoriteFoods" name="FavoriteFoods" type="text" value="Sushi" /><br /> <label for="Birthday_Day">Day</label><br /> <input class="text-box single-line" id="Birthday_Day" name="Birthday.Day" type="text" value="0" /><br /> <label for="Birthday_Month">Month</label><br /> <input class="text-box single-line" id="Birthday_Month" name="Birthday.Month" type="text" value="0" /><br /> <input type="submit" value="Submit" /> </form>
现在这是完整的。 在Create Post控制器操作中设置一个断点来validation。 不要用列表,但是因为它不会工作。 看到我的问题关于IEnumerable使用EditorTemplates的更多。
我的回答是基于Mahmoud Moravej的回答,包括Ivan Zlatev的评论。
public static MvcHtmlString PartialFor<TModel, TProperty>(this HtmlHelper<TModel> helper, System.Linq.Expressions.Expression<Func<TModel, TProperty>> expression, string partialViewName) { string name = ExpressionHelper.GetExpressionText(expression); object model = ModelMetadata.FromLambdaExpression(expression, helper.ViewData).Model; StringBuilder htmlFieldPrefix = new StringBuilder(); if (helper.ViewData.TemplateInfo.HtmlFieldPrefix != "") { htmlFieldPrefix.Append(helper.ViewData.TemplateInfo.HtmlFieldPrefix); htmlFieldPrefix.Append(name == "" ? "" : "." + name); } else htmlFieldPrefix.Append(name); var viewData = new ViewDataDictionary(helper.ViewData) { TemplateInfo = new System.Web.Mvc.TemplateInfo { HtmlFieldPrefix = htmlFieldPrefix.ToString() } }; return helper.Partial(partialViewName, model, viewData); }
编辑:对于嵌套的部分呈现Mohamoud的答案是不正确的。 只有在必要时,您才需要将新前缀追加到旧前缀。 这在最新的答案中并不清楚(:
这是一个老问题,但对于任何人到达这里寻找解决scheme,请考虑使用EditorFor
,如在https://stackoverflow.com/a/29809907/456456中的评论中所build议的。; 要从部分视图移动到编辑器模板,请按照下列步骤操作。
-
validation您的部分视图绑定到ComplexType 。
-
将您的局部视图移动到当前视图文件夹的子文件夹EditorTemplates或共享文件夹。 现在,它是一个编辑器模板。
-
将
@Html.Partial("_PartialViewName", Model.ComplexType)
更改为@Html.EditorFor(m => m.ComplexType, "_EditorTemplateName")
。 编辑器模板是可选的,如果它是复杂types的唯一模板。
Htmlinput元素将自动命名为ComplexType.Fieldname
。
我也遇到了这个问题,经过很多痛苦,我发现重新devise我的接口,我不需要回发嵌套的模型对象更容易。 这迫使我改变我的界面工作stream程:当然,我现在要求用户分两步做我梦寐以求的工作,但新方法的可用性和代码可维护性现在对我来说更有价值。
希望这有助于一些。
您可以为RenderPartial添加一个帮助器,该帮助器会接收前缀并将其popup到ViewData中。
public static void RenderPartial(this HtmlHelper helper,string partialViewName, object model, string prefix) { helper.ViewData["__prefix"] = prefix; helper.RenderPartial(partialViewName, model); }
然后又一个连接ViewData值的辅助函数
public static void GetName(this HtmlHelper helper, string name) { return string.Concat(helper.ViewData["__prefix"], name); }
所以在视图中…
<% Html.RenderPartial("AnotherViewModelControl", Model.Child, "Child.") %>
在部分…
<%= Html.TextBox(Html.GetName("Name"), Model.Name) %>
PartailFor为asp.net Core 2万一有人需要它。
public static ModelExplorer GetModelExplorer<TModel, TResult>(this IHtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TResult>> expression) { if (expression == null) throw new ArgumentNullException(nameof(expression)); return ExpressionMetadataProvider.FromLambdaExpression(expression, htmlHelper.ViewData, htmlHelper.MetadataProvider); } public static IHtmlContent PartialFor<TModel, TResult>(this IHtmlHelper<TModel> helper, Expression<Func<TModel, TResult>> expression, string partialViewName, string prefix = "") { var modelExplorer = helper.GetModelExplorer(expression); helper.ViewData.TemplateInfo.HtmlFieldPrefix += prefix; return helper.Partial(partialViewName, modelExplorer.Model, helper.ViewData); }
像你一样,我添加Prefix属性(一个string)到我的模型绑定input名称之前追加我ViewModels。 (YAGNI防止下面)
更优雅的解决scheme可能是具有此属性的基本视图模型,以及一些检查视图模型是否从此基础派生的HtmlHelpers,如果是这样,则将前缀附加到input名称。
希望有所帮助,
担
在你打电话给RenderPartial之前,你呢?
<% ViewData["Prefix"] = "Child."; %> <% Html.RenderPartial("AnotherViewModelControl", Model.Child) %>
然后在你的部分你有
<%= Html.TextBox(ViewData["Prefix"] + "Name", Model.Name) %>