Suppose you have a model like so:
class Foo
{
public int A {get; set;}
public int B {get; set;}
}
class SomeModel
{
public List<Foo> Foos { get; set; }
}
In a razor view on the ASP.NET mvc framework, you can do the following:
@model SomeModel
@for(int i = 0; i < Model.Foos.Count; ++i)
{
Html.EditorFor(x => x.Foos[i]);
}
And the razor engine will happily spit out the correct html containing the index, and will call the editor template with the correct indexed instance.
The EditorFor
method is a static extension method with the signature
public static MvcHtmlString EditorFor<TModel, TValue>(
this HtmlHelper<TModel> html,
Expression<Func<TModel, TValue>> expression
)
From the signature, it is clear that it is simply taking an expression, and the only context is coming from the HtmlHelper instance.
I have done very limited Expression
tree processing, but from what I have seen, I can't see any way that this static method could know the information that it is somehow magically getting.
How can the EditorFor
method figure out the index for generating html names and get the correct instance to pass to the editor template?
The advantages of EditorFor is that your code is not tied to an <input type="text" . So if you decide to change something to the aspect of how your textboxes are rendered like wrapping them in a div you could simply write a custom editor template ( ~/Views/Shared/EditorTemplates/string.
The Html. Editor() or Html. EditorFor() extension methods generate HTML elements based on the data type of the model object's property. The following table list the data types and releted HTML elements: DataType.
EditorFor does not allow for styling as there are no parameters for additional attributes. The reason for this is because the EditorFor doesn't always generate a single element as it can be overridden. To style a specific type of element you need to use the specific editor you want to use.
You are passing it an expression, not the value of x.Foos[i]
. MVC then evaluates that expression and figures out that you gave it a collection with an index.
You would get the same result if you removed your entire loop and did:
Html.EditorFor(x => x.Foos)
MVC will then automatically render the editor template for all elements of the collection and generate proper names.
You can read more about how MVC handles display/editor templates here: Link
EDIT : To see this in action, here's a random piece of code I scribbled:
List<string> list = new List<string>() { "A", "B", "C" };
var tester = new ExpressionTester<List<string>>(list);
var item = tester.Foo(p => p[0]);
You'll also need this class:
public class ExpressionTester<TModel>
{
private TModel _list;
public ExpressionTester(TModel list)
{
_list = list;
}
public TValue Foo<TValue>(Expression<Func<TModel, TValue>> expression)
{
var func = expression.Compile();
return func.Invoke(_list);
}
}
Stick a breakpoint in Foo() and look at the parameter expression
in debug. You'll find under Body -> Arguments the index you passed with the expression. Under Body -> Method you'll see that it is in fact a generic list.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With