MVC3 Html.Editor 目标字典未绑定到客户端

发布于 2024-10-27 00:50:35 字数 3033 浏览 0 评论 0原文

我的视图模型沿着

EditViewModel
    SomeUserType User
        Dictionary<string, string> Claims

在我看来,我试图将其绑定如下,

@{
    int 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.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++;
    }
}

这将按照我的预期在编辑屏幕上呈现一系列键值对文本框。然而,即使声明字典中有 KeyValuePair,文本框也始终为空。

如果我填写 KVP 文本框的值并将表单发送回我的控制器,我确实会将值正确地模型绑定回我的 User.Claims 字典中。

我错过了什么,导致视图加载时绑定无法获得正确的值?

编辑:附加信息,基本上我试图弄清楚这对于 MVC 本质上是如何工作的。我直接从核心 MVC (2) 对象模板创建了上面的视图 Brad Wilson 在此讨论。我试图在 Razor 中找到它的确切代码,但我在任何地方都找不到它...离题...将其转换为 Razor 我最终得到的

@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>    
}

主要区别是对 @if ( ViewData.TemplateInfo.TemplateDepth > 4) 这将允许 MVC 深入到我的字典中,然后它可以正确绑定所有内容。然而,经过进一步的调试询问,我发现当它绑定 Key 属性时,它实际上只看到 @Html.Editor("Key") 这是如何工作的?

显然,编辑器必须对 ViewData.ModelMetadata.Properties 有一定的了解,但是它决定了 ViewData.TemplateInfo.Visited() 的结果,即它能够正确放置正确的东西,就在这一点上,我不知道什么是发生在幕后,在这个 foreach 循环内部, @Html.Editor("Key") 做了任何事情。

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 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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

我为君王 2024-11-03 00:50:35

尝试这样:

@{
    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++;
    }
}

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++;
    }
}
烂人 2024-11-03 00:50:35

@Html.Editor(string name) 将为 ViewData 中的字段名称生成编辑器。如果 ViewData 不包含您的对象,则必须使用另一个重载:@Html.Editor(string name, object viewData)。

在您的情况下,您可以将 @Html.Label(string.Format("User.Claims[{0}].Key", i)) 替换为 @Html.Label(string.Format("User.Claims[{0}) ].Key", i),User.Claims[i].Value)

@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)

淡写薰衣草的香 2024-11-03 00:50:35
   @{
 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>

 }
    }
   @{
 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>

 }
    }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文