MVC3 Html.Editor targeting dictionary is not binding down to the client
My view model is along the lines of
EditViewModel
SomeUserType User
Dictionary<string, string> Claims
In my view I'm trying to bind this as follows
@{
int i = 0;
foreach (var key in Model.User.Claims.Keys)
{
<div class="editor">
<input type="hidden" value="@i" name="User.Claims.Index">
<div 开发者_JAVA百科class="editor-label">
@Html.Label(string.Format("User.Claims[{0}].Key", i))
</div>
<div class="editor-field">
@Html.Editor(string.Format("User.Claims[{0}].Key", i))
</div>
<div class="editor-label">
@Html.Label(string.Format("User.Claims[{0}].Value", i))
</div>
<div class="editor-field">
@Html.Editor(string.Format("User.Claims[{0}].Value", i))
</div>
</div>
i++;
}
}
Which renders out the series of Key Value pair text boxes on the edit screen as I would expect. However the text boxes are always empty even though there are KeyValuePairs in the Claims dictionary.
If I fill in values for the KVP text boxes and post the form back to my controller I do get the values correctly model bound back into my User.Claims
Dictionary.
What am I missing that is preventing the binding from having the correct values in it as the view loads?
Edit: Additional information, basically I'm trying to figure out how exactly this works for MVC inherently. I created my view above directly from the core MVC (2) object template that Brad Wilson discusses here. I tried to find the exact code for this in Razor but I couldn't find it at all anywhere... digressing... Converting this to Razor I ended up with
@if (ViewData.TemplateInfo.TemplateDepth > 4)
{
@ViewData.ModelMetadata.SimpleDisplayText
}
else
{
<div class="editor">
@foreach (var prop in ViewData.ModelMetadata.Properties
.Where(pm => pm.ShowForEdit && !ViewData.TemplateInfo.Visited(pm)))
{
if (prop.HideSurroundingHtml)
{
@Html.Editor(prop.PropertyName)
}
else
{
if (!String.IsNullOrEmpty(Html.Label(prop.PropertyName)
.ToHtmlString()))
{
<div class="editor-label"> @Html.Label(prop.PropertyName)
</div>
}
<div class="editor-field">
@Html.Editor(prop.PropertyName)
@Html.ValidationMessage(prop.PropertyName)
</div>
}
}
</div>
}
The main difference is the edit to the @if (ViewData.TemplateInfo.TemplateDepth > 4)
which will allow MVC to dive deep enough that it reaches my dictionary it can then bind everything correctly. However upon further interrogation with debugging I see when it binds the Key property it actually sees just @Html.Editor("Key")
how does this work?
Clearly Editor must have some kind of knowledge of ViewData.ModelMetadata.Properties and however it determines ViewData.TemplateInfo.Visited()'s result that it's able to correctly place the right stuff, just at this point I'm at a loss of what's happening behind the scenes that somehow inside of this foreach loop that @Html.Editor("Key") does ANYTHING.
Try like this:
@{
var i = 0;
foreach (var key in Model.User.Claims.Keys)
{
<div class="editor">
<input type="hidden" value="@i" name="User.Claims.Index" />
<div class="editor-label">
@Html.Label(string.Format("User.Claims[{0}].Key", i))
</div>
<div class="editor-field">
@Html.TextBox(string.Format("User.Claims[{0}].Key", i), key)
</div>
<div class="editor-label">
@Html.Label(string.Format("User.Claims[{0}].Value", i))
</div>
<div class="editor-field">
@Html.TextBox(string.Format("User.Claims[{0}].Value", i), Model.User.Claims[key])
</div>
</div>
i++;
}
}
@Html.Editor(string name) will generate editor for field name in ViewData. If ViewData not contains your object, you must used another overload: @Html.Editor(string name, object viewData).
In your case, you can replace @Html.Label(string.Format("User.Claims[{0}].Key", i)) with @Html.Label(string.Format("User.Claims[{0}].Key", i),User.Claims[i].Value)
@{
foreach (KeyValuePair<string, string> item in Model.ShippingCarrier)
{
<tr>
<td>
@Html.TextBox(item.Key.ToString(), item.Key, new { @class = "w50" }) : @Html.TextBox(item.Key.ToString(), item.Key, new { @class = "w50" })
</td>
</tr>
}
}
精彩评论