6

I have a controller with two actions:

[AcceptVerbs("GET")]
    public ActionResult Add()
    {
        PrepareViewDataForAddAction();
        return View();
    }


[AcceptVerbs("POST")]
    public ActionResult Add([GigBinderAttribute]Gig gig, FormCollection formCollection)
    {
        if (ViewData.ModelState.IsValid)
        {
            GigManager.Save(gig);
            return RedirectToAction("Index", gig.ID);
        }
        PrepareViewDataForAddAction();
        return View(gig);
    }

As you can see, when the form posts its data, the Add action uses a GigBinder (An implemenation of IModelBinder)

In this binder I have:

 if (int.TryParse(bindingContext.HttpContext.Request.Form["StartDate.Hour"], out hour))
        {
           gig.StartDate.Hour = hour;
        }
        else
        {
            bindingContext.ModelState.AddModelError("Doors", "You need to tell us when the doors open");
        }

The form contains a text box with id "StartDate.Hour".

As you can see above, the GigBinder tests to see that the user has typed in an integer into the textbox with id "StartDate.Hour". If not, a model error is added to the modelstate using AddModelError.

Since the gigs property gigs.StartDate.Hour is strongly typed, I cannot set its value to, for example, "TEST" if the user has typed this into the forms textbox.

Hence, I cant set the value of gigs.StartDate.Hour since the user has entered a string rather than an integer.

Since the Add Action returns the view and passes the model (return View(gig);) if the modelstate is invalid, when the form is re-displayed with validation mssages, the value "TEST" is not displayed in the textbox. Instead, it will be the default value of gig.StartDate.Hour.

How do I get round this problem? I really stuck!

4

3 回答 3

2

我认为问题在于您的 ViewModel 与您的 View 匹配不够紧密。在 MVC 中,您的 ViewModel 尽可能与您的 View 匹配非常重要。

在您的 ViewModel 中,您假设一个整数,但在您的 View 中,您使用 TextBox 来呈现属性,这将允许任何类型的文本。这里存在不匹配,您在尝试映射它们时遇到的困难是不匹配的症状。

我认为您应该:
1. 将 ViewModel 属性的类型更改为字符串,然后在您的控制器中进行验证以确保输入的字符串实际上是一个数字,或者:
2. 将 View 呈现的控件更改为仅允许通过自定义控件或 Javascript 验证输入数字(如@Qun Wang 建议的那样)

就个人而言,我推荐选项 1。这样 ViewModel 不依赖于 View 实现。

于 2010-04-29T02:04:50.747 回答
1

Could you do this in your PrepareViewDataForAddAction method?..

if (!ViewData.ModelState.IsValid)
    {
        ViewData["StartDate.Hour"] = "Error";
    }

The other fields on the form will still populate based on the properties of the Gig object.

于 2009-01-06T14:05:52.527 回答
1

我认为您需要先进行一些基本的客户端验证。不允许它发布到服务器。

于 2010-04-10T09:27:08.287 回答