【问题标题】:MVC nerd dinner CreateView not displaying EventDateMVC 书呆子晚餐 CreateView 不显示 EventDate
【发布时间】:2013-01-13 17:52:50
【问题描述】:

我目前正在阅读使用 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));
    }

这里是 View 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);
        }
    }
}

【问题讨论】:

    标签: asp.net-mvc-3 nerddinner


    【解决方案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 =&gt; 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 实现时,您会发现其他方法可以以不那么冗长的方式完成相同的任务。坚持下去!

    【讨论】:

    • 视图中的所有 TextBox 和 ValidationMessage 实例是否都相同?
    • 是的,你明白了!我刚刚用更多细节更新了答案,但是是的,一般来说,您应该在处理强类型视图时使用@Html.*For helpers
    • 好的,这似乎解决了原来的问题,但现在我已将所有 @Html.TextBox() 替换为 @Html.TextBoxFor@Html.ValidationMessage 处理错误时,它不再在输入后应用红色 astrix框或输入框本身的红色高亮,尽管它仍然在页面顶部显示错误。
    • 1) 你的 Html.ValidationSummary 应该在 Using Html.Form 里面。 2)你能发布你的模型代码吗?
    • 确定我能坚持 2 分钟。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-10-25
    • 1970-01-01
    • 2023-03-03
    • 2011-07-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多