当表单重新显示失败值时,输入验证错误到文本框
我问过 问题 了解为什么在我的应用程序中,当我使用模型绑定来验证模型时,文本框被突出显示(即红色边框和粉红色阴影背景应用于文本框)(TryUpdateModel() ),但当我手动验证时(ModelState.AddModelError)则不然。到现在已经2天了,没有任何答复。我自己尝试了一切,但没有成功。所以,我决定以不同的方式问这个问题。
根据我的理解,ModelBinding 处理请求的方式如下。
- ModelBinding 从 httpcontext 获取传入值
- 它实例化该模型的一个对象
- 尝试将这些值解析为该对象
- 如果属性有问题,它会使用 ModelState.AddModelError 来标记有问题的属性。
- 重新显示视图
这是我的问题当重新显示表单时:
对于其值无效而无法突出显示的文本框正在做什么?
我知道 Site.css 中有几个类,例如作为应用于文本框的 .input-validation-error 和 .field-validation-error 。也许 ModelBinding 在内部使用诸如 AddCss("#MyTextBox", ".input-validation-error") 之类的命令。
如果我知道它是如何工作的,我可以(也许)手动应用它并解决我的问题。
编辑
根据@Ian Galloway的要求,这里是代码
public class RegistrationController : Controller
{
public FormViewModel formViewModel;
private RegistrationService _registrationService = new RegistrationService();
private SaveService _saveService = new SaveService();
protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
var serialized = Request.Form["formViewModel"];
if (serialized != null)
{
formViewModel = (FormViewModel)new MvcSerializer()
.Deserialize(serialized);
TryUpdateModel(formViewModel);
}
else
formViewModel = (FormViewModel)TempData["formViewModel"]
?? new FormViewModel();
}
protected override void OnResultExecuted(ResultExecutedContext filterContext)
{
if (filterContext.Result is RedirectToRouteResult)
TempData["formViewModel"] = formViewModel;
}
public ActionResult SetUpOrganization(string cancel, string nextButton)
{
if ((nextButton != null) && ModelState.IsValid)
{
if (formViewModel.navigationData.IsAReview)
return RedirectToAction("RequestPreview");
return RedirectToAction("ChooseTypeOrganization");
}
ViewData["Cities"] = _registrationService.Get_Cities();
formViewModel.navigationData.NextAction = "SetUpOrganization";
return View(formViewModel);
}
public ActionResult ChooseTypeOrganization(string backButton, string nextButton)
{
if (backButton != null)
{
return RedirectToAction("SetUpOrganization");
}
if (nextButton != null)
{
if (formViewModel.navigationData.IsAReview)
return RedirectToAction("RequestPreview");
return RedirectToAction("DocumentsPresented");
}
ViewData["TypeOrganization"] = _registrationService.Get_AllTypeOrganization();
formViewModel.navigationData.NextAction = "ChooseTypeOrganization";
return View(formViewModel);
}
public ActionResult DocumentsPresented(string backButton, string nextButton)
{
if (backButton != null)
{
return RedirectToAction("ChooseTypeOrganization");
}
if (nextButton != null)
{
//Validation
if (string.IsNullOrEmpty(formViewModel.registrationData.DocumentPresente))
{
ModelState.AddModelError("DocumentPresente", "Veuillez préciser votre
autorisation");
return View(formViewModel);
}
//Navigation
if (formViewModel.navigationData.IsAReview)
return RedirectToAction("RequestPreview");
return RedirectToAction("PeopleRecommended");
}
formViewModel.navigationData.NextAction = "DocumentsPresented";
return View(formViewModel);
}
public ActionResult PeopleRecommended(string backButton, string nextButton, string deleteButton,
string deletePerson, string addPerson)
{
if (backButton != null)
{
return RedirectToAction("DocumentsPresented");
}
if (nextButton != null)
{
ModelState.Clear();
if (formViewModel.registrationData.PeopleRecommended.Count == 0)
ModelState.AddModelError("", "Il faut absolument designer un responsable pour la requête");
//
if (ModelState.IsValid)
{
if (formViewModel.navigationData.IsAReview)
return RedirectToAction("RequestPreview");
return RedirectToAction("StateObjectifs");
}
else
{
return View(formViewModel);
}
}
//
if (addPerson != null)
{
if (ModelState.IsValid)
{
formViewModel.registrationData.PeopleRecommended.Add(
_registrationService.Translate_PersonToBeAdded_Into_Person(formViewModel.personToBeAdded)
);
formViewModel.personToBeAdded = null;
}
else
{
formViewModel.navigationData.NextAction = "PeopleRecommended";
return View(formViewModel);
}
}
if (deleteButton != null)
{
formViewModel.registrationData.PeopleRecommended.RemoveAt(int.Parse(deletePerson));
}
ViewData.ModelState.Clear();
formViewModel.navigationData.NextAction = "PeopleRecommended";
return View(formViewModel);
}
[ValidateInput(false)]
public ActionResult StateObjectifs(string backButton, string nextButton)
{
if (backButton != null)
{
return RedirectToAction("PeopleRecommended");
}
if (nextButton != null)
{
if (string.IsNullOrEmpty(formViewModel.registrationData.Objective) ||
string.IsNullOrEmpty(formViewModel.registrationData.RequestDetails))
{
if (string.IsNullOrEmpty(formViewModel.registrationData.Objective))
ModelState.AddModelError("Objective", "Vous devez préciser l'objectif de votre requête");
if (string.IsNullOrEmpty(formViewModel.registrationData.RequestDetails))
ModelState.AddModelError("RequestDetails", "Vous devez préciser le contenu de votre requête");
return View(formViewModel);
}
if (formViewModel.navigationData.IsAReview)
return RedirectToAction("RequestPreview");
return RedirectToAction("StateDeadLine");
}
return View(formViewModel);
}
public ActionResult StateDeadLine(string backButton, string nextButton)
{
if (backButton != null)
{
return RedirectToAction("StateObjectifs");
}
if (nextButton != null)
{
if (formViewModel.registrationData.ChooseDifferentDeadLine)
{
if (formViewModel.registrationData.DifferentDeadline == null ||
string.IsNullOrEmpty(formViewModel.registrationData.ReasonsForDifferentDeadLine))
{
if (formViewModel.registrationData.DifferentDeadline == null)
ModelState.AddModelError("DifferentDeadline", "Clickez pour choisir une nouvelle date");
if (string.IsNullOrEmpty(formViewModel.registrationData.ReasonsForDifferentDeadLine))
ModelState.AddModelError("ReasonsForDifferentDeadLine", "Expliquez brievement pour quoi ce changement");
return View(formViewModel);
}
}
return RedirectToAction("RequestPreview");
}
formViewModel.navigationData.NextAction = "StateDeadLine";
return View(formViewModel);
}
public ActionResult RequestPreview(string backButton, string nextButton, string reviewInput, string save)
{
if (backButton != null)
{
return RedirectToAction("StateDeadLine");
}
if (nextButton != null)
{
_saveService.Save_FormViewModel(formViewModel);
return RedirectToAction("Index", "Home");
}
if (reviewInput != null)
{
formViewModel.navigationData.IsAReview = true;
return RedirectToAction(RedirectHelpers.RedirectReviewAction(formViewModel.navigationData, reviewInput));
}
ViewData["TypeOrganization_Summary"] = _registrationService.Get_TypeOrganization_Summary(
formViewModel.registrationData.TypeOrganizationID );
if (save != null)
{
_saveService.Save_FormViewModel(formViewModel);
return RedirectToAction("Index", "Home");
}
formViewModel.navigationData.NextAction = "RequestPreview";
return View(formViewModel);
}
}
编辑号2
我选择了其中一个视图(因为他们都遇到了同样的问题)。该视图名为 StateObjectifs.aspx
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<!-- Script Begin -->
<script src="../../Scripts/tiny_mce/tiny_mce.js" type="text/javascript"></script>
<script type = "text/javascript">
tinyMCE.init({
mode: "textareas",
theme: "advanced",
theme_advanced_toolbar_location: "top",
theme_advanced_toolbar_align: "left",
theme_advanced_statusbar_location: "bottom",
theme_advanced_resizing: true
});
</script>
<!-- End Script -->
<fieldset id = "StateObjectifs">
<legend>Etape 5:</legend>
<div id = "left-pane" style = "width:700px">
<%using (Html.BeginForm("StateObjectifs", "Registration"))
{ %>
<%: Html.ValidationSummary() %>
<% = Html.Serialize("formViewModel", Model) %>
<table>
<tr>
<th><% = Html.LabelFor(x=>x.registrationData.Objective) %></th>
<td><% = Html.TextBoxFor(x=>x.registrationData.Objective) %>
<%: Html.ValidationMessageFor(x =>x.registrationData.Objective, "*")%></td>
</tr>
<tr>
<th colspan = "2"><% = Html.LabelFor(x =>x.registrationData.RequestDetails) %></th>
</tr>
<tr>
<td colspan = "2">
<% = Html.TextAreaFor(x =>x.registrationData.RequestDetails, 10, 75, null) %>
</td>
</tr>
</table>
</div>
<div id = "right-pane">
<ul>
<li>Les cases pour lesquelles le titre se termine par (*) sont obligatoires</li>
<li>Pour mieux vous servir, veuillez décrire clairement de manière concise
votre requête. Par exemple: <i>Les données de l'USAID sur le secteur santé pour l'année 2009</i></li>
</ul>
</div>
<div class = "clear"></div>
<fieldset>
<% Html.RenderPartial("NavigationView", Model.navigationData); %>
</fieldset>
</fieldset>
<%} %>
谢谢你的帮助。
I've asked a question to know why, in my application, textboxes are being highlighted (i.e. red border and pink-shaded backgroung are applied to the textbox) when I use modelbinding to validate the model (TryUpdateModel()) but not when I validate manually (ModelState.AddModelError). It has been 2 days now without any answer. I've tried every thing myself without succes. So, I decide to ask the question differently.
The way I understand IT, here's how ModelBinding treats a request.
- ModelBinding get incoming values from httpcontext
- It instantiate an object of that model
- Tries to parse those values to the object
- If there's someting wrong with a property, it uses ModelState.AddModelError to mark properties that has something wrong with them.
- Re-displays the view
Here's my question When the form is re-displayed:
What's being done for the textboxes whose values are not valid to get highlighted?
I know that there's few classes in Site.css, such as .input-validation-error and .field-validation-error that get applied to the textbox. Maybe ModelBinding uses internally a command such as AddCss("#MyTextBox", ".input-validation-error").
If I know how it works, I can (maybe) aplly it manually and solve my problem.
EDIT
As requested by @Ian Galloway, here's the code
public class RegistrationController : Controller
{
public FormViewModel formViewModel;
private RegistrationService _registrationService = new RegistrationService();
private SaveService _saveService = new SaveService();
protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
var serialized = Request.Form["formViewModel"];
if (serialized != null)
{
formViewModel = (FormViewModel)new MvcSerializer()
.Deserialize(serialized);
TryUpdateModel(formViewModel);
}
else
formViewModel = (FormViewModel)TempData["formViewModel"]
?? new FormViewModel();
}
protected override void OnResultExecuted(ResultExecutedContext filterContext)
{
if (filterContext.Result is RedirectToRouteResult)
TempData["formViewModel"] = formViewModel;
}
public ActionResult SetUpOrganization(string cancel, string nextButton)
{
if ((nextButton != null) && ModelState.IsValid)
{
if (formViewModel.navigationData.IsAReview)
return RedirectToAction("RequestPreview");
return RedirectToAction("ChooseTypeOrganization");
}
ViewData["Cities"] = _registrationService.Get_Cities();
formViewModel.navigationData.NextAction = "SetUpOrganization";
return View(formViewModel);
}
public ActionResult ChooseTypeOrganization(string backButton, string nextButton)
{
if (backButton != null)
{
return RedirectToAction("SetUpOrganization");
}
if (nextButton != null)
{
if (formViewModel.navigationData.IsAReview)
return RedirectToAction("RequestPreview");
return RedirectToAction("DocumentsPresented");
}
ViewData["TypeOrganization"] = _registrationService.Get_AllTypeOrganization();
formViewModel.navigationData.NextAction = "ChooseTypeOrganization";
return View(formViewModel);
}
public ActionResult DocumentsPresented(string backButton, string nextButton)
{
if (backButton != null)
{
return RedirectToAction("ChooseTypeOrganization");
}
if (nextButton != null)
{
//Validation
if (string.IsNullOrEmpty(formViewModel.registrationData.DocumentPresente))
{
ModelState.AddModelError("DocumentPresente", "Veuillez préciser votre
autorisation");
return View(formViewModel);
}
//Navigation
if (formViewModel.navigationData.IsAReview)
return RedirectToAction("RequestPreview");
return RedirectToAction("PeopleRecommended");
}
formViewModel.navigationData.NextAction = "DocumentsPresented";
return View(formViewModel);
}
public ActionResult PeopleRecommended(string backButton, string nextButton, string deleteButton,
string deletePerson, string addPerson)
{
if (backButton != null)
{
return RedirectToAction("DocumentsPresented");
}
if (nextButton != null)
{
ModelState.Clear();
if (formViewModel.registrationData.PeopleRecommended.Count == 0)
ModelState.AddModelError("", "Il faut absolument designer un responsable pour la requête");
//
if (ModelState.IsValid)
{
if (formViewModel.navigationData.IsAReview)
return RedirectToAction("RequestPreview");
return RedirectToAction("StateObjectifs");
}
else
{
return View(formViewModel);
}
}
//
if (addPerson != null)
{
if (ModelState.IsValid)
{
formViewModel.registrationData.PeopleRecommended.Add(
_registrationService.Translate_PersonToBeAdded_Into_Person(formViewModel.personToBeAdded)
);
formViewModel.personToBeAdded = null;
}
else
{
formViewModel.navigationData.NextAction = "PeopleRecommended";
return View(formViewModel);
}
}
if (deleteButton != null)
{
formViewModel.registrationData.PeopleRecommended.RemoveAt(int.Parse(deletePerson));
}
ViewData.ModelState.Clear();
formViewModel.navigationData.NextAction = "PeopleRecommended";
return View(formViewModel);
}
[ValidateInput(false)]
public ActionResult StateObjectifs(string backButton, string nextButton)
{
if (backButton != null)
{
return RedirectToAction("PeopleRecommended");
}
if (nextButton != null)
{
if (string.IsNullOrEmpty(formViewModel.registrationData.Objective) ||
string.IsNullOrEmpty(formViewModel.registrationData.RequestDetails))
{
if (string.IsNullOrEmpty(formViewModel.registrationData.Objective))
ModelState.AddModelError("Objective", "Vous devez préciser l'objectif de votre requête");
if (string.IsNullOrEmpty(formViewModel.registrationData.RequestDetails))
ModelState.AddModelError("RequestDetails", "Vous devez préciser le contenu de votre requête");
return View(formViewModel);
}
if (formViewModel.navigationData.IsAReview)
return RedirectToAction("RequestPreview");
return RedirectToAction("StateDeadLine");
}
return View(formViewModel);
}
public ActionResult StateDeadLine(string backButton, string nextButton)
{
if (backButton != null)
{
return RedirectToAction("StateObjectifs");
}
if (nextButton != null)
{
if (formViewModel.registrationData.ChooseDifferentDeadLine)
{
if (formViewModel.registrationData.DifferentDeadline == null ||
string.IsNullOrEmpty(formViewModel.registrationData.ReasonsForDifferentDeadLine))
{
if (formViewModel.registrationData.DifferentDeadline == null)
ModelState.AddModelError("DifferentDeadline", "Clickez pour choisir une nouvelle date");
if (string.IsNullOrEmpty(formViewModel.registrationData.ReasonsForDifferentDeadLine))
ModelState.AddModelError("ReasonsForDifferentDeadLine", "Expliquez brievement pour quoi ce changement");
return View(formViewModel);
}
}
return RedirectToAction("RequestPreview");
}
formViewModel.navigationData.NextAction = "StateDeadLine";
return View(formViewModel);
}
public ActionResult RequestPreview(string backButton, string nextButton, string reviewInput, string save)
{
if (backButton != null)
{
return RedirectToAction("StateDeadLine");
}
if (nextButton != null)
{
_saveService.Save_FormViewModel(formViewModel);
return RedirectToAction("Index", "Home");
}
if (reviewInput != null)
{
formViewModel.navigationData.IsAReview = true;
return RedirectToAction(RedirectHelpers.RedirectReviewAction(formViewModel.navigationData, reviewInput));
}
ViewData["TypeOrganization_Summary"] = _registrationService.Get_TypeOrganization_Summary(
formViewModel.registrationData.TypeOrganizationID );
if (save != null)
{
_saveService.Save_FormViewModel(formViewModel);
return RedirectToAction("Index", "Home");
}
formViewModel.navigationData.NextAction = "RequestPreview";
return View(formViewModel);
}
}
EDIT number 2
I have choosed one of the view (as all of them experience the same issue). The view is called StateObjectifs.aspx
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<!-- Script Begin -->
<script src="../../Scripts/tiny_mce/tiny_mce.js" type="text/javascript"></script>
<script type = "text/javascript">
tinyMCE.init({
mode: "textareas",
theme: "advanced",
theme_advanced_toolbar_location: "top",
theme_advanced_toolbar_align: "left",
theme_advanced_statusbar_location: "bottom",
theme_advanced_resizing: true
});
</script>
<!-- End Script -->
<fieldset id = "StateObjectifs">
<legend>Etape 5:</legend>
<div id = "left-pane" style = "width:700px">
<%using (Html.BeginForm("StateObjectifs", "Registration"))
{ %>
<%: Html.ValidationSummary() %>
<% = Html.Serialize("formViewModel", Model) %>
<table>
<tr>
<th><% = Html.LabelFor(x=>x.registrationData.Objective) %></th>
<td><% = Html.TextBoxFor(x=>x.registrationData.Objective) %>
<%: Html.ValidationMessageFor(x =>x.registrationData.Objective, "*")%></td>
</tr>
<tr>
<th colspan = "2"><% = Html.LabelFor(x =>x.registrationData.RequestDetails) %></th>
</tr>
<tr>
<td colspan = "2">
<% = Html.TextAreaFor(x =>x.registrationData.RequestDetails, 10, 75, null) %>
</td>
</tr>
</table>
</div>
<div id = "right-pane">
<ul>
<li>Les cases pour lesquelles le titre se termine par (*) sont obligatoires</li>
<li>Pour mieux vous servir, veuillez décrire clairement de manière concise
votre requête. Par exemple: <i>Les données de l'USAID sur le secteur santé pour l'année 2009</i></li>
</ul>
</div>
<div class = "clear"></div>
<fieldset>
<% Html.RenderPartial("NavigationView", Model.navigationData); %>
</fieldset>
</fieldset>
<%} %>
Thanks for helping.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
实际上,这个突出显示是由渲染文本框的 html 帮助程序执行的。它使用给定的键检查模型状态中是否存在错误,并在必要时添加必要的 CSS 类。
Actually this highlighting is performed by the html helpers that render the textboxes. It checks if there's an error in the model state with the given key and it adds the necessary CSS classes if necessary.
我怀疑您遇到的问题是您传递到 ModelState.AddModelError 的“key”参数必须与表单上匹配控件的名称匹配。
(否则,您如何期望视图引擎知道在错误状态下渲染哪个控件?)
I suspect the problem you are having is that the "key" parameter you pass into ModelState.AddModelError must match the name of the matching control on the form.
(Otherwise, how would you expect the view engine to know which control to render in an error state?)
突出显示是由应用于文本框的 CSS 完成的。所以你需要添加下面的css:
}
The highlighting is being done by CSS which applies to the text-box. So you need to add the css below:
}