1

現在、MVS 2010 を使用して MVC チュートリアルの Nerd Dinner を実行しています。ステップ 7 まで完了しましたが、作成画面に移動すると、それが正しくないことに気付きました。

  1. タイトル入力ボックスにはViewBag.Title空白ではなく が含まれているようです。
  2. EventDate今から 7 日後に自動的に設定される必要がある場合、入力ボックスは空白です。

チュートリアルの前半でこのようになったことを覚えていません。

Create を処理する からの抜粋を次にDinnersController.cs示します。

    //
    // 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);
        }
    }
}
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は、渡す文字列で指定された name 属性を持つテキスト ボックスをレンダリングします。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 に答える