asp.net-mvc ASP.NET MVC 部分视图:输入名称前缀
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1488890/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
ASP.NET MVC partial views: input name prefixes
提问by queen3
Suppose I have ViewModel like
假设我有类似的 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; }
}
In the view I can render a partial with
在视图中,我可以渲染部分
<% Html.RenderPartial("AnotherViewModelControl", Model.Child) %>
In the partial I'll do
在部分我会做
<%= Html.TextBox("Name", Model.Name) %>
or
<%= Html.TextBoxFor(x => x.Name) %>
However, the problem is that both will render name="Name" while I need to have name="Child.Name" in order for model binder to work properly. Or, name="Child2.Name" when I render the second property using the same partial view.
但是,问题是两者都会呈现 name="Name" 而我需要 name="Child.Name" 以便模型绑定器正常工作。或者,当我使用相同的局部视图呈现第二个属性时,name="Child2.Name"。
How do I make my partial view automatically recognize the required prefix? I can pass it as a parameter but this is too inconvenient. This is even worse when I want for example to render it recursively. Is there a way to render partial views with a prefix, or, even better, with automatic reconition of the calling lambda expression so that
如何让我的局部视图自动识别所需的前缀?我可以将它作为参数传递,但这太不方便了。例如,当我想递归渲染它时,情况就更糟了。有没有办法用前缀渲染局部视图,或者更好的是,自动重新识别调用的 lambda 表达式,以便
<% Html.RenderPartial("AnotherViewModelControl", Model.Child) %>
will automatically add correct "Child." prefix to the generated name/id strings?
将自动添加正确的“孩子”。生成的名称/ID 字符串的前缀?
I can accept any solution, including 3-rd party view engines and libraries - I actually use Spark View Engine (I "solve" the problem using its macros) and MvcContrib, but did not find a solution there. XForms, InputBuilder, MVC v2 - any tool/insight that provide this functionality will be great.
我可以接受任何解决方案,包括第 3 方视图引擎和库 - 我实际上使用 Spark 视图引擎(我使用其宏“解决”了问题)和 MvcContrib,但没有在那里找到解决方案。XForms、InputBuilder、MVC v2 - 任何提供此功能的工具/见解都会很棒。
Currently I think about coding this myself but it seems like a waste of time, I can't believe this trivial stuff is not implemented already.
目前我正在考虑自己编写代码,但这似乎是在浪费时间,我不敢相信这些琐碎的东西还没有实现。
A lot of manual solutions may exists, and all of them are welcome. For example, I can force my partials to be based off IPartialViewModel<T> { public string Prefix; T Model; }. But I'd rather prefer some existing/approved solution.
可能存在许多手动解决方案,欢迎所有这些解决方案。例如,我可以强制我的部分基于 IPartialViewModel<T> { public string Prefix; T型;}. 但我更喜欢一些现有/批准的解决方案。
UPDATE: there's a similar question with no answer here.
更新:有没有回答类似的问题在这里。
采纳答案by Mahmoud Moravej
You can extend Html helper class by this :
您可以通过以下方式扩展 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);
}
and simply use it in your views like this :
并简单地在您的视图中使用它,如下所示:
<%= Html.PartialFor(model => model.Child, "_AnotherViewModelControl") %>
and you will see everything is ok!
你会看到一切正常!
回答by Jokin
so far, i was searching for the same thing I have found this recent post:
到目前为止,我正在寻找与我在最近的帖子中发现的相同的东西:
http://davybrion.com/blog/2011/01/prefixing-input-elements-of-partial-views-with-asp-net-mvc/
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" }
})
%>
回答by asoifer1879
My answer, based on the answer of Mahmoud Moravej including the comment of Ivan Zlatev.
我的回答基于 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);
}
Edit: The Mohamoud's answer is incorrect for nested partial rendering. You need to append the new prefix to the old prefix, only if it is necessary. This was not clear in the latest answers (:
编辑:对于嵌套部分渲染,Mohamoud 的答案是不正确的。仅在必要时才需要将新前缀附加到旧前缀。这在最新的答案中并不清楚(:
回答by R. Schreurs
This is an old question, but for anyone arriving here looking for a solution, consider using EditorFor, as suggested in a comment in https://stackoverflow.com/a/29809907/456456. To move from a partial view to an editor template, follow these steps.
这是一个老问题,但对于任何到达这里寻找解决方案的人,请考虑使用EditorFor,如https://stackoverflow.com/a/29809907/456456中的评论中所建议的。要从局部视图移动到编辑器模板,请按照以下步骤操作。
Verify that your partial view is bound to ComplexType.
Move your partial view to a subfolder EditorTemplatesof the current view folder, or to the folder Shared. Now, it is an editor template.
Change
@Html.Partial("_PartialViewName", Model.ComplexType)to@Html.EditorFor(m => m.ComplexType, "_EditorTemplateName"). The editor template is optional if it's the only template for the complex type.
验证您的分部视图是否绑定到ComplexType。
将局部视图移动到当前视图文件夹的子文件夹EditorTemplates或文件夹Shared。现在,它是一个编辑器模板。
更改
@Html.Partial("_PartialViewName", Model.ComplexType)为@Html.EditorFor(m => m.ComplexType, "_EditorTemplateName")。如果编辑器模板是复杂类型的唯一模板,则它是可选的。
Html Input elements will automatically be named ComplexType.Fieldname.
Html 输入元素将自动命名ComplexType.Fieldname。
回答by Nick Larsen
Using MVC2 you can achieve this.
使用 MVC2 您可以实现这一点。
Here is the strongly typed view:
这是强类型视图:
<%@ 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>
Here is the strongly typed view for the child class (which must be stored in a subfolder of the view directory called EditorTemplates):
这是子类的强类型视图(必须存储在名为 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 />
Here is the controller:
这是控制器:
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);
}
}
Here are the custom classes:
以下是自定义类:
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; }
}
And the output source:
和输出源:
<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>
Now this is complete. Set a breakpoint in the Create Post controller action to verify. Don't use this with lists however because it wont work. See my question on using EditorTemplates with IEnumerable for more on that.
现在已经完成了。在 Create Post 控制器操作中设置断点以进行验证。但是不要将它与列表一起使用,因为它不起作用。有关更多信息,请参阅我关于将 EditorTemplates 与 IEnumerable 结合使用的问题。
回答by Rahma Samaroon
PartailForfor asp.net Core 2 in case someone needs it.
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);
var viewData = new ViewDataDictionary(helper.ViewData);
viewData.TemplateInfo.HtmlFieldPrefix += prefix;
return helper.Partial(partialViewName, modelExplorer.Model, viewData);
}
回答by Matt Kocaj
I came across this issue also and after much pain i found it was easier to redesign my interfaces such that i didn't need to post back nested model objects. This forced me to change my interface workflows: sure i now require the user to do in two steps what i dreamed of doing on one, but the usability and code maintainability of the new approach is of greater value to me now.
我也遇到了这个问题,在经历了很多痛苦之后,我发现重新设计我的界面更容易,这样我就不需要回发嵌套的模型对象。这迫使我改变了我的界面工作流程:当然,我现在要求用户分两步完成我梦想在一个步骤上完成的工作,但是现在新方法的可用性和代码可维护性对我来说更有价值。
Hope this helps some.
希望这对一些人有所帮助。
回答by Anthony Johnston
You could add a helper for the RenderPartial which takes the prefix and pops it in the ViewData.
您可以为 RenderPartial 添加一个帮助程序,它采用前缀并将其弹出到 ViewData 中。
public static void RenderPartial(this HtmlHelper helper,string partialViewName, object model, string prefix)
{
helper.ViewData["__prefix"] = prefix;
helper.RenderPartial(partialViewName, model);
}
Then a further helper which concatenates the ViewData value
然后是连接 ViewData 值的进一步助手
public static void GetName(this HtmlHelper helper, string name)
{
return string.Concat(helper.ViewData["__prefix"], name);
}
and so in the view ...
所以在视图中......
<% Html.RenderPartial("AnotherViewModelControl", Model.Child, "Child.") %>
in the partial ...
在部分...
<%= Html.TextBox(Html.GetName("Name"), Model.Name) %>
回答by Daniel Elliott
Like you, I add Prefix property (a string) to my ViewModels which I append before my model bound input names. (YAGNI preventing the below)
像你一样,我将 Prefix 属性(一个字符串)添加到我的 ViewModels 中,我将它附加在我的模型绑定输入名称之前。(YAGNI 防止以下情况)
A more elegant solution might be a base view model that has this property and some HtmlHelpers that check if the view model derives from this base and if so append the prefix to the input name.
一个更优雅的解决方案可能是具有此属性的基础视图模型和一些 HtmlHelpers,用于检查视图模型是否源自此基础,如果是,则将前缀附加到输入名称。
Hope that helps,
希望有所帮助,
Dan
担
回答by Anthony Johnston
How about just before you call RenderPartial you do
在你调用 RenderPartial 之前你做的怎么样
<% ViewData["Prefix"] = "Child."; %>
<% Html.RenderPartial("AnotherViewModelControl", Model.Child) %>
Then in your partial you have
然后在你的部分你有
<%= Html.TextBox(ViewData["Prefix"] + "Name", Model.Name) %>

