问题
I have an EditorFor:
<%: Html.EditorFor(model => model.Client, "ClientTemplate", new { editing = false })%>
This will bind coming down to the view fine (as expected) but will not bind bind back when the model gets posted. This is due to the form id's not being prefixed with "Client."
Usually in this situation i just pass in model and then bind the inputs to model.Client.PropertyName in the Template but this is not an option in this case as the template is used on two different viewmodels (that have client on).
Any suggestions on getting this to bind properly?
Many thanks, Kohan.
Addendum
It seems this was a misunderstanding on my part, the issue as i now understand it is that fluentHtml does not work inside EditorFor Templates. (The same goes for this fix, which as it turns out was not needed as EditorFor will prefix for me automatically if i replace the fluentHtml with normal mvc html helpers)
回答1:
Try something like:
<% Html.BeginHtmlFieldPrefixScope("Client") {
Html.EditorFor(model => model.Client, "ClientTemplate", new { editing = false });
<% } %>
Every field you make with EditorFor, LabelFor and the likes will be prefixed.
EDIT: Here's the extension method I'm using, sorry!
public static IDisposable BeginHtmlFieldPrefixScope(this HtmlHelper html, string htmlFieldPrefix)
{
return new HtmlFieldPrefixScope(html.ViewData.TemplateInfo, htmlFieldPrefix);
}
...and the class...
private class HtmlFieldPrefixScope : IDisposable
{
private readonly TemplateInfo templateInfo;
private readonly string previousHtmlFieldPrefix;
public HtmlFieldPrefixScope(TemplateInfo templateInfo, string htmlFieldPrefix)
{
this.templateInfo = templateInfo;
previousHtmlFieldPrefix = templateInfo.HtmlFieldPrefix;
templateInfo.HtmlFieldPrefix = htmlFieldPrefix;
}
public void Dispose()
{
templateInfo.HtmlFieldPrefix = previousHtmlFieldPrefix;
}
}
See the link mentioned by Kohan in the comments below.
回答2:
MVC3 HTML Name Clashing
Cutting and pasting that does not work in MVC3. To get the extension to work, I had to create a class file:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace incMvcSite.Classes {
public static class HtmlPrefixScopeExtensions {
public static IDisposable BeginHtmlFieldPrefixScope(this HtmlHelper html, string htmlFieldPrefix) {
return new HtmlFieldPrefixScope(html.ViewData.TemplateInfo, htmlFieldPrefix);
}
private class HtmlFieldPrefixScope : IDisposable {
private readonly TemplateInfo templateInfo;
private readonly string previousHtmlFieldPrefix;
public HtmlFieldPrefixScope(TemplateInfo templateInfo, string htmlFieldPrefix) {
this.templateInfo = templateInfo;
previousHtmlFieldPrefix = templateInfo.HtmlFieldPrefix;
templateInfo.HtmlFieldPrefix = htmlFieldPrefix;
}
public void Dispose() {
templateInfo.HtmlFieldPrefix = previousHtmlFieldPrefix;
}
}
}
}
In the Razor (.cshtml) file, I added the following:
@using incMvcSite.Classes
@using(Html.BeginHtmlFieldPrefixScope("Permission")) {
<fieldset>
<legend>Permission</legend>
// The Html.EditorFor's would go here...
</fieldset>
}
Notice the using to bring me extension class into scope. That allows the second using line to work.
Now the problem is that when posting back, the object is not updated. In my controller, I used a second parameter to specify my prefix:
TryUpdateModel(modelUser.Permission, "Permission");
This added the prefix to all field in the HTML, and the TryUpdateModel loaded the object with prefixed control names. Now you can properly namespace your controls for embedded edit lists, and for partial views of models with the same property names.
来源:https://stackoverflow.com/questions/4606686/forcing-editorfor-to-prefix-input-items-on-view-with-class-name