为什么 ValidationMessageFor 在此实例中不显示我的验证消息?

发布于 2024-10-31 15:42:51 字数 1469 浏览 2 评论 0原文

我有一个视图模型,其中包含一个类的 5 个实例作为子属性。这些子属性使用分部视图呈现,如下所示:

<%Html.RenderPartial("_EntryItemForm", Model.EntryItem1, new ViewDataDictionary { TemplateInfo = new System.Web.Mvc.TemplateInfo { HtmlFieldPrefix = "EntryItem1" } }); %>        
<%Html.RenderPartial("_EntryItemForm", Model.EntryItem2, new ViewDataDictionary { TemplateInfo = new System.Web.Mvc.TemplateInfo { HtmlFieldPrefix = "EntryItem2" } }); %>
<%Html.RenderPartial("_EntryItemForm", Model.EntryItem3, new ViewDataDictionary { TemplateInfo = new System.Web.Mvc.TemplateInfo { HtmlFieldPrefix = "EntryItem3" } }); %>
<%Html.RenderPartial("_EntryItemForm", Model.EntryItem4, new ViewDataDictionary { TemplateInfo = new System.Web.Mvc.TemplateInfo { HtmlFieldPrefix = "EntryItem4" } }); %>
<%Html.RenderPartial("_EntryItemForm", Model.EntryItem5, new ViewDataDictionary { TemplateInfo = new System.Web.Mvc.TemplateInfo { HtmlFieldPrefix = "EntryItem5" } }); %>

在分部视图中,我有以下内容(仅显示一个字段):

<%: Html.LabelFor<EntryItemForm, string>(x => x.ItemName)%>
<%: Html.TextBoxFor<EntryItemForm, string>(x => x.ItemName)%>
<%: Html.ValidationMessageFor(x => x.ItemName)%>

标签和文本框均使用正确的 id、名称等以及默认模型进行渲染活页夹完美地处理了一切。

不幸的是,即使 ModelState 包含 ItemName 字段的错误,ValidationMessage 也永远不会出现。如果我将 ValidationSummary 添加到父视图,则会显示错误。通常我只会使用 ValidationSummary 并继续,但我正在研究的设计需要内联验证消息。

有谁知道为什么会这样?

I've got a view model that contains 5 instances of a class as sub-properties. These sub-properties are rendered using a partial view, as follows:

<%Html.RenderPartial("_EntryItemForm", Model.EntryItem1, new ViewDataDictionary { TemplateInfo = new System.Web.Mvc.TemplateInfo { HtmlFieldPrefix = "EntryItem1" } }); %>        
<%Html.RenderPartial("_EntryItemForm", Model.EntryItem2, new ViewDataDictionary { TemplateInfo = new System.Web.Mvc.TemplateInfo { HtmlFieldPrefix = "EntryItem2" } }); %>
<%Html.RenderPartial("_EntryItemForm", Model.EntryItem3, new ViewDataDictionary { TemplateInfo = new System.Web.Mvc.TemplateInfo { HtmlFieldPrefix = "EntryItem3" } }); %>
<%Html.RenderPartial("_EntryItemForm", Model.EntryItem4, new ViewDataDictionary { TemplateInfo = new System.Web.Mvc.TemplateInfo { HtmlFieldPrefix = "EntryItem4" } }); %>
<%Html.RenderPartial("_EntryItemForm", Model.EntryItem5, new ViewDataDictionary { TemplateInfo = new System.Web.Mvc.TemplateInfo { HtmlFieldPrefix = "EntryItem5" } }); %>

Within the partial view, I have the following (showing one field only):

<%: Html.LabelFor<EntryItemForm, string>(x => x.ItemName)%>
<%: Html.TextBoxFor<EntryItemForm, string>(x => x.ItemName)%>
<%: Html.ValidationMessageFor(x => x.ItemName)%>

The label and textboxes both render with the correct ids, names and so on, and the default model binder handles everything perfectly.

Unfortunately, even when the ModelState contains an error for the ItemName field, the ValidationMessage never appears. If I add a ValidationSummary to the parent view, the error is displayed. Normally I'd just use a ValidationSummary and move on, but the design I'm working to requires inline validation messages.

Does anyone have any idea why this might be?

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

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

发布评论

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

评论(4

深者入戏 2024-11-07 15:42:51

对于正在谷歌搜索此问题的人:

问题是由于使用 HtmlFieldPrefix 时 ModelState 未以正确的方式传递到部分视图而引起的。这个 html 助手解决了问题(对我来说)并且验证错误显示正确:

public static void RenderPartialWithPrefix(this HtmlHelper helper, string partialViewName, object model, string prefix)
    {
        ViewDataDictionary WDD = new ViewDataDictionary {TemplateInfo = new System.Web.Mvc.TemplateInfo { HtmlFieldPrefix = prefix } };

        foreach(string key in helper.ViewData.ModelState.Keys)
        {
            if(key.StartsWith(prefix+"."))
            {
                foreach (ModelError err in helper.ViewData.ModelState[key].Errors)
                {
                  if(!string.IsNullOrEmpty(err.ErrorMessage))
                    WDD.ModelState.AddModelError(key, err.ErrorMessage);
                  if (err.Exception != null)
                      WDD.ModelState.AddModelError(key, err.Exception);
                }
                WDD.ModelState.SetModelValue(key, helper.ViewData.ModelState[key].Value);
            }
        }

        helper.RenderPartial(partialViewName,model,WDD);
    }

只需使用它来渲染带有前缀的部分视图

@{Html.RenderPartialWithPrefix("_StructureEditSharePartView", Model.sharePart,"sharePart");}

For someone who are googling for this trouble:

Problem caused in a reason that ModelState doesn't passes to partial view in a right way when HtmlFieldPrefix used. This html helper solved the problem(for me) and validation errors displays correct:

public static void RenderPartialWithPrefix(this HtmlHelper helper, string partialViewName, object model, string prefix)
    {
        ViewDataDictionary WDD = new ViewDataDictionary {TemplateInfo = new System.Web.Mvc.TemplateInfo { HtmlFieldPrefix = prefix } };

        foreach(string key in helper.ViewData.ModelState.Keys)
        {
            if(key.StartsWith(prefix+"."))
            {
                foreach (ModelError err in helper.ViewData.ModelState[key].Errors)
                {
                  if(!string.IsNullOrEmpty(err.ErrorMessage))
                    WDD.ModelState.AddModelError(key, err.ErrorMessage);
                  if (err.Exception != null)
                      WDD.ModelState.AddModelError(key, err.Exception);
                }
                WDD.ModelState.SetModelValue(key, helper.ViewData.ModelState[key].Value);
            }
        }

        helper.RenderPartial(partialViewName,model,WDD);
    }

just use it for render partial views with prefix

@{Html.RenderPartialWithPrefix("_StructureEditSharePartView", Model.sharePart,"sharePart");}
冷了相思 2024-11-07 15:42:51

也许元数据中包含验证错误的字段名称与 TextBoxFor 帮助程序生成的字段名称不匹配。使用编辑器模板怎么样?这样你就不需要担心前缀、设置模板信息、验证问题......

所以你可以定义 (~/Views/Shared/EditorTemplates/TypeOfEntryItem.ascx):

<%@ Control 
    Language="C#" 
    Inherits="System.Web.Mvc.ViewUserControl<AppName.Models.TypeOfEntryItem>"
%>
<%= Html.LabelFor(x => x.ItemName) %>
<%= Html.TextBoxFor(x => x.ItemName) %>
<%= Html.ValidationMessageFor(x => x.ItemName) %>

并在主视图很简单:

<% using (Html.BeginForm()) { %>
    <%= Html.EditorFor(x => x.EntryItem1) %>
    <%= Html.EditorFor(x => x.EntryItem2) %>
    <%= Html.EditorFor(x => x.EntryItem3) %>
    <%= Html.EditorFor(x => x.EntryItem4) %>
    <%= Html.EditorFor(x => x.EntryItem5) %>

    <input type="submit" value="OK" />
<% } %>

如果您不想在模型上创建 5 个属性,这甚至适用于集合。您可以有一个简单的属性:

public IEnumerable<TypeOfEntryItem> EntryItems { get; set; }

然后:

<% using (Html.BeginForm()) { %>
    <%= Html.EditorFor(x => x.EntryItems) %>
    <input type="submit" value="OK" />
<% } %>

它将呈现集合中每个项目的编辑器模板,当然还负责生成正确的 ID、名称……

Maybe the name of the field containing validation error in the metadata doesn't match the name of the field generated by the TextBoxFor helper. How about using editor templates? This way you don't need to bother with prefixes, setting template infos, problems with validation, ...

So you could define (~/Views/Shared/EditorTemplates/TypeOfEntryItem.ascx):

<%@ Control 
    Language="C#" 
    Inherits="System.Web.Mvc.ViewUserControl<AppName.Models.TypeOfEntryItem>"
%>
<%= Html.LabelFor(x => x.ItemName) %>
<%= Html.TextBoxFor(x => x.ItemName) %>
<%= Html.ValidationMessageFor(x => x.ItemName) %>

and in the main view simply:

<% using (Html.BeginForm()) { %>
    <%= Html.EditorFor(x => x.EntryItem1) %>
    <%= Html.EditorFor(x => x.EntryItem2) %>
    <%= Html.EditorFor(x => x.EntryItem3) %>
    <%= Html.EditorFor(x => x.EntryItem4) %>
    <%= Html.EditorFor(x => x.EntryItem5) %>

    <input type="submit" value="OK" />
<% } %>

This even works with collections if you don't want to bother creating 5 properties on your model. You could have a simple property:

public IEnumerable<TypeOfEntryItem> EntryItems { get; set; }

and then:

<% using (Html.BeginForm()) { %>
    <%= Html.EditorFor(x => x.EntryItems) %>
    <input type="submit" value="OK" />
<% } %>

which will render the editor template for each item in the collection and of course take care of generating proper ids, names, ...

醉梦枕江山 2024-11-07 15:42:51

将 Html.ViewData 对象添加到 ViewDataDictionary 的构造函数中也可以。

<%Html.RenderPartial("_EntryItemForm", Model.EntryItem1, new ViewDataDictionary(Html.ViewData) { TemplateInfo = new System.Web.Mvc.TemplateInfo { HtmlFieldPrefix = "EntryItem1" } }); %>

它的作用是将当前上下文(包括 ModelState)提供给新创建的 ViewDataDictionary,而不是为其提供单独的上下文。这样,就不需要扩展方法了。

Adding the Html.ViewData object to the constructor of the ViewDataDictionary also works.

<%Html.RenderPartial("_EntryItemForm", Model.EntryItem1, new ViewDataDictionary(Html.ViewData) { TemplateInfo = new System.Web.Mvc.TemplateInfo { HtmlFieldPrefix = "EntryItem1" } }); %>

What this does is, it gives the current context (including the ModelState) to the newly created ViewDataDictionary, instead of giving it a separate context. This way, there is no need for an extension method.

仅一夜美梦 2024-11-07 15:42:51

http://www.dalsoft.co.uk/blog/index.php/2010/04/26/mvc-2-templates/#Complex_Types" dalsoft.co.uk/blog/index.php/2010/04/26/mvc-2-templates/#Complex_Types

关于您关于 IEnumerable 的最后一个问题,请查看上面的文章以获得一个不错的解决方法。另外,我希望有人能回答您关于使 htmlFieldPrefix 工作的问题...“优雅”与否,如果您不支持验证消息,那么支持视图的显示/渲染/处理就没有意义。我正在尝试让 EditorFor 也为我工作(现在),但如果我有时间并返回使其与 RenderPartial 一起工作,我会回到这里并发布解决方案。

对于那些可能通过谷歌搜索问题找到解决办法的人来说,原因是 ModelState 包含诸如“ComplexObjectProperty.ModelProperty”之类的键,但 ValidationMessageFor 尝试仅查找“ModelProperty”。重大监督。

http://www.dalsoft.co.uk/blog/index.php/2010/04/26/mvc-2-templates/#Complex_Types

Regarding your last question about IEnumerable, check out the article above for a decent workaround. Also, I wish someone would answer your question about making things work with the htmlFieldPrefix ... "elegant" or not, there's no point in supporting the display/rendering/processing of the view if you can't support the validation messages. I'm trying to get EditorFor to work for me as well (now) but if I ever get the time and return to making it work with RenderPartial, I'll come back here and post the solution.

For those who may find their way here by Googling the problem, the cause is that the ModelState contains keys like "ComplexObjectProperty.ModelProperty" but the ValidationMessageFor tries to look up just "ModelProperty". Major oversight.

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