1

我目前正在使用 MVS 2010 浏览 MVC 教程 Nerd Dinner 我已经到了第 7 步,但我刚刚注意到,当我现在进入创建屏幕时,它并不完全正确。

  1. 标题输入框似乎包含ViewBag.Title而不是空白。
  2. 输入框为EventDate空白时应自动设置为从现在起7天。

我不记得在教程的前面是这样的。

这是DinnersController.cs处理 Create 的代码片段:

    //
    // GET: /Dinners/Create

    public ActionResult Create()
    {
        Dinner dinner = new Dinner()
        {
            EventDate = DateTime.Now.AddDays(7)
        };

        return View(new DinnerFormViewModel(dinner));
    }

    //
    // POST: /Dinners/Create

    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult Create(Dinner dinner)
    {
        if (ModelState.IsValid)
        {
            try
            {
                dinner.HostedBy = "SomeUser";

                dinnerRepository.Add(dinner);
                dinnerRepository.Save();

                return RedirectToAction("Details", new { id = dinner.DinnerID });
            }
            catch
            {
                ModelState.AddModelErrors(dinner.GetRuleViolations());
            }

        }

        return View(new DinnerFormViewModel(dinner));
    }

这是视图 Create.cshtml

@model NerdDinner.Models.DinnerFormViewModel

@{
    ViewBag.Title = "Host a Dinner";
}

<h2>Host a Dinner</h2>

@Html.ValidationSummary("Please correct the errors and try again")

@using (Html.BeginForm()) {

    <fieldset>
        <p>
            @Html.LabelFor(model => Model.Dinner.Title)
            <br />
            @Html.TextBox("Title")
            @Html.ValidationMessage("Title", "*")
        </p>
        <p>
            @Html.LabelFor(model => Model.Dinner.EventDate)
            <br />
            @Html.TextBox("EventDate")
            @Html.ValidationMessage("EventDate", "*")
        </p>
        <p>
            @Html.LabelFor(model => Model.Dinner.Description)
            <br />
            @Html.TextArea("Description")
            @Html.ValidationMessage("Description", "*")
        </p>
        <p>
            @Html.LabelFor(model => Model.Dinner.Address)
            <br />
            @Html.TextBox("Address")
            @Html.ValidationMessage("Address", "*")
        </p>
        <p>
            @Html.LabelFor(model => Model.Countries)
            <br />
            @Html.DropDownList("Country", Model.Countries)
            @Html.ValidationMessage("Country", "*")
        </p>
        <p>
            @Html.LabelFor(model => Model.Dinner.ContactPhone)
            <br />
            @Html.TextBox("ContactPhone")
            @Html.ValidationMessage("ContactPhone", "*")
        </p>
        <p>
            @Html.LabelFor(model => Model.Dinner.Latitude)
            <br />
            @Html.TextBox("Latitude")
            @Html.ValidationMessage("Latitude", "*")
        </p>
        <p>
            <label for="Longitude">Longitude:</label>
            <br />
            @Html.TextBox("Longitude")
            @Html.ValidationMessage("Longitude", "*")
        </p>
        <p>
            <input type="submit" value="Create" />
        </p>
    </fieldset>
}

<div>
    @Html.ActionLink("Back to List", "Index")
</div>

最后是浏览器中的输出:

输出

有人知道我错过了什么吗?

编辑 - 添加晚餐模型

using System;
using System.Collections.Generic;
using System.Data.Linq;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Text; //added this - not in tut
using System.Text.RegularExpressions; //added this - not in tut

namespace NerdDinner.Models
{
    [Bind(Include = "Title,Description,EventDate,Address,Country,ContactPhone,Latitude,Longitude")]
    public partial class Dinner
    {

        public bool IsValid
        {
            get { return (GetRuleViolations().Count() == 0); }
        }

        public IEnumerable<RuleViolation> GetRuleViolations()
        {
            if (String.IsNullOrEmpty(Title))
                yield return new RuleViolation("Title required", "Title");

            if (String.IsNullOrEmpty(Description))
                yield return new RuleViolation("Description required", "Description");

            if (String.IsNullOrEmpty(HostedBy))
                yield return new RuleViolation("HostedBy required", "HostedBy");

            if (String.IsNullOrEmpty(Address))
                yield return new RuleViolation("Address required", "Address");

            if (String.IsNullOrEmpty(Country))
                yield return new RuleViolation("Country required", "Country");

            if (String.IsNullOrEmpty(ContactPhone))
            {
                yield return new RuleViolation("ContactPhone required", "ContactPhone");
            }
            else
            {
                if (!PhoneValidator.IsValidNumber(ContactPhone, Country))
                    yield return new RuleViolation("Phone# does not match country", "ContactPhone");
            }


                yield break;
        }

        partial void OnValidate(ChangeAction action)
        {
            if (!IsValid)
                throw new ApplicationException("Rule voilations prevent saving");
        }

    }

    public class RuleViolation
    {
        public string ErrorMessage { get; private set; }
        public string PropertyName { get; private set; }

        public RuleViolation(string errorMessage, string propertyName)
        {
            ErrorMessage = errorMessage;
            PropertyName = propertyName;
        }
    }

    public class PhoneValidator
    {
        static IDictionary<string, Regex> countryRegex = new Dictionary<string, Regex>()
        {
            { "USA", new Regex("^[2-9]\\d{2}-\\d{3}-\\d{4}$")},
            { "UK", new Regex("(^1300\\d{6}$)|(^1800|1900|1902\\d{6}$)|(^0[2|3|7|8]{1}[0-9]{8}$)|(^04\\decimal{2,3}\\decimal{6}$)")},
            { "Netherlands", new Regex("(^\\+[0-9]{2}|^\\+[0-9]{2}\\(0\\)|^\\(\\+[0-9]{2}\\)\\(0\\)|^00[0-9]{2}|^0)([0-9]{9}$|[0-9\\-\\s]{10}$)")},

        };

        public static bool IsValidNumber(string phoneNumber, string country)
        {
            if (country != null && countryRegex.ContainsKey(country))
                return countryRegex[country].IsMatch(phoneNumber);
            else
                return false;
        }

        public static IEnumerable<string> Countries
        {
            get
            {
                return countryRegex.Keys;
            }
        }
    }

    public class DinnerFormViewModel
    {

        // Properties
        public Dinner Dinner { get; private set; }
        public SelectList Countries { get; private set; }

        // Contructor
        public DinnerFormViewModel(Dinner dinner)
        {
            Dinner = dinner;
            Countries = new SelectList(PhoneValidator.Countries, dinner.Country);
        }
    }
}
4

1 回答 1

1

你应该使用@Html.TextboxFor而不是@Html.Textbox

<p>
            @Html.LabelFor(model => Model.Dinner.EventDate)
            <br />
            @Html.TextBoxFor(model => Model.Dinner.EventDate)
            @Html.ValidationMessageFor(model => Model.Dinner.EventDate)
        </p>

基本@Html.Textbox将呈现一个文本框,其名称属性在您传递的字符串中指定。MVC 将查看 ViewBag 以查看是否有任何带有该键的项目来填充文本框(这就是您的 Title 属性使用视图顶部的页面标题的原因),但不会将视图输入绑定到实际模型或随模型发送的任何预填充数据。通过使用 TextBoxFor(或 labelFor 等),这会将输入与实际模型属性联系起来。这也是 DataAnnotations 应用于表单的方式。我所说的最后一句话是这个意思。假设这是您模型的一部分

public class DinnerViewModel{
  [DisplayName("Dinner Location")]
  [Required(ErrorMessage="You must specify a location")]
  public string Location {get;set;}
}

在您看来,您将使用 @Html.*For 方法呈现您需要的部分(就像您做标签一样)

<p>
   @Html.LabelFor(model => Model.Location )
   <br />
   @Html.TextBoxFor(model => Model.Location)
   @Html.ValidationMessageFor(model => Model.Location )
</p>

应该像这样呈现一些 HTML(不包括错误消息)

<p>
  <label for="Location">Dinner Location</label>
  <br/>
  <input type="text" name="Location" id="Location"/>
  *the validation related stuff*
</p>

附录

为了使您的验证与您正在使用的方法一起工作,您必须稍微更改您的 yield return 语句。如果您仔细查看 HTML 源代码中实际晚餐对象的属性的 id,您会发现它们呈现为“ Dinner.Title”或“ Dinner.Description”。这是因为这就是它们在模型中的存储方式(记得使用model => Model.Dinner.EventDate吗?)这将呈现一个 id 为 ' Dinner.EventDate' 的元素。

鉴于此,您需要更新从模型的 RuleViolation 部分返回的字符串:

public IEnumerable<RuleViolation> GetRuleViolations()
        {
            if (String.IsNullOrEmpty(Title))
                yield return new RuleViolation("Title required", "Dinner.Title");

            if (String.IsNullOrEmpty(Description))
                yield return new RuleViolation("Description required", "Dinner.Description");

            if (String.IsNullOrEmpty(HostedBy))
                yield return new RuleViolation("HostedBy required", "Dinner.HostedBy");

            if (String.IsNullOrEmpty(Address))
                yield return new RuleViolation("Address required", "Dinner.Address");

            if (String.IsNullOrEmpty(Country))
                yield return new RuleViolation("Country required", "Country");

            if (String.IsNullOrEmpty(ContactPhone))
            {
                yield return new RuleViolation("ContactPhone required", "Dinner.ContactPhone");
            }
            else
            {
                if (!PhoneValidator.IsValidNumber(ContactPhone, Country))
                    yield return new RuleViolation("Phone# does not match country", "Dinner.ContactPhone");
            }


                yield break;
        }

现在,您的 RuleViolations 将匹配实际的输入 ID,一切都将再次闪亮和令人敬畏。这似乎有点工作,但由于您正在学习教程,我不想过多地推动您的方式。但是,当您探索 .NET MVC 实现时,您会发现其他方法可以以不那么冗长的方式完成相同的任务。坚持下去!

于 2013-01-13T17:56:00.227 回答