没有 'IEnumerable<SelectListItem>' 类型的 ViewData 项具有键 'Practice' - MVC5

There is no ViewData item of type 'IEnumerable<SelectListItem>' that has the key 'Practice' - MVC5

I am very new to MVC and have just added a cascading drop down to my create page so when a Practice is selected the Optician drop down is populated with the names of opticians that work at that practice.

型号:

public class Booking
{
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public Guid BookingId { get; set; }

    [ForeignKey("Patient")]
    public Guid PatientId { get; set; }
    public virtual Patient Patient { get; set; }
    public IEnumerable<SelectListItem> PatientList { get; set; }

    [ForeignKey("Practice")]
    public Guid PracticeId { get; set; }
    public virtual Practice Practice { get; set; }
    public IEnumerable<SelectListItem> PracticeList { get; set; }

    [ForeignKey("Optician")]
    public Guid OpticianId { get; set; }
    public virtual Optician Optician { get; set; }
    public IEnumerable<SelectListItem> OpticiansList { get; set; }

    [Display(Name = "Date")]
    [DataType(DataType.Date)]
    [DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:dd/MM/yyyy}")]
    public DateTime Date { get; set; }

    [ForeignKey("Time")]
    public Guid? TimeId { get; set; }
    public virtual Time Time { get; set; }
    public IEnumerable<SelectListItem> TimeList { get; set; }
    
    public bool isAvail { get; set; }
}

我的控制器:

// GET: Bookings1/Create
    public ActionResult Create()
    {

        var practices = new SelectList(db.Practices, "PracticeId", "PracticeName");
        ViewData["Practice"] = practices;

        Booking booking = new Booking();
        ConfigureCreateModel(booking);

        return View(booking);

                }

    public void ConfigureCreateModel(Booking booking)
    {


        booking.PatientList = db.Patients.Select(p => new SelectListItem()
        {
            Value = p.PatientId.ToString(),
            Text = p.User.FirstName
        });

        
         
        booking.TimeList = db.Times.Select(t => new SelectListItem()
        {
            Value = t.TimeId.ToString(),
            Text = t.AppointmentTime
        });


    }

    // POST: Bookings1/Create
    // To protect from overposting attacks, please enable the specific properties you want to bind to, for 
    // more details see http://go.microsoft.com/fwlink/?LinkId=317598.
    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Create(Booking booking)
    {
        // to ensure date is in the future
        if (ModelState.IsValidField("Date") && DateTime.Now > booking.Date)
        {
            ModelState.AddModelError("Date", "Please enter a date in the future");
        }

        // Sets isAvail to false
        booking.isAvail = false;

        //Checks if model state is not valid
        if (!ModelState.IsValid)
        {
            ConfigureCreateModel(booking);
            return View(booking); // returns user to booking page
        }
        else // if model state is Valid
        {
            // Generates a new booking Id
            booking.BookingId = Guid.NewGuid();
            // Adds booking to database
            db.Bookings.Add(booking);
            // Saves changes to Database
            db.SaveChanges();
            // Redirects User to Booking Index
            return RedirectToAction("Index");
        }
    }

我的看法:

<script src="~/Scripts/jquery-1.10.2.js"></script>

<script>
$(document).ready(function () {
    $("#Optician").prop("disabled", true);
    $("#Practice").change(function () {
        $.ajax({
            url : "@Url.Action("Opticians","Bookings")",
            type : "POST",
            data : {Id : $(this).val() }
        }).done(function (opticianList) {
            $("#Optician").empty();
            for (var i = 0; i < opticianList.length; i++) {
                $("#Optician").append("<option>" + opticianList[i] + "</option>");
            }
            $("#Optician").prop("disabled", false);
        });
    });
});
</script>


@using (Html.BeginForm())
{
@Html.AntiForgeryToken()

<div class="form-horizontal">
        <h4>Booking</h4>
        <hr />
        @Html.ValidationSummary(true, "", new { @class = "text-danger" })
        <div class="form-group">
            @Html.LabelFor(model => model.PatientId, new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.DropDownListFor(model => model.PatientId, Model.PatientList, "-Please select-",  new { @class = "form-control" })
                @Html.ValidationMessageFor(model => model.PatientId, "", new { @class = "text-danger" })
            </div>
        </div>

        
        <div class="form-group">
            @Html.LabelFor(model => model.PracticeId, new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.DropDownList("Practice", ViewData["Practice"] as SelectList,"-Please Select-", new { @class = "form-control" })
                @Html.ValidationMessageFor(model => model.PracticeId, "", new { @class = "text-danger" })
            </div>
        </div>


        <div class="form-group">
            @Html.Label("Select Optician :", new { @class = "col-md-2 control-label" })
            <div class="col-md-10">
                <select id="Optician"></select>
            </div>
        </div>


        <div class="form-group">
            @Html.LabelFor(model => model.Date, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.Date, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.Date, "", new { @class = "text-danger" })
            </div>
        </div>

        
        <div class="form-group">
            @Html.LabelFor(model => model.TimeId, new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.DropDownListFor(model => model.TimeId, Model.TimeList, "-Please select-", new { @class = "form-control" })
                @Html.ValidationMessageFor(model => model.TimeId, "", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            <div class="col-md-offset-2 col-md-10">
                <input type="submit" value="Create" class="btn btn-default" />
            </div>
        </div>
    </div>
}
        <div>
            @Html.ActionLink("Back to List", "Index")
        </div>

级联下拉菜单正常工作,但是当我单击按钮创建约会时抛出以下异常:

异常:

An exception of type 'System.InvalidOperationException' occurred in System.Web.Mvc.dll but was not handled in user code

Additional information: There is no ViewData item of type 'IEnumerable' that has the key 'Practice'.

如有任何帮助,我们将不胜感激。 谢谢

您的模型已经包含一个属性 实践集合

public IEnumerable<SelectListItem> PracticeList { get; set; }

虽然它不应该包含

public virtual Practice Practice { get; set; }

在 GET 方法中,您为练习创建了一个新的 SelectList,但不是将其分配给模型 属性,而是使用 [=24= 将其添加到 ViewData ]

ViewData["Practice"] = practices;

然后在视图中使用

@Html.DropDownList("Practice", ViewData["Practice"] as SelectList, ..)

它甚至没有绑定到您模型中的 属性,并且永远不会 post 返回任何东西。然后,当您 return 视图中的 POST 方法(因为您的模式将始终无效)时,您不会为 ViewData["Practice"] 赋值,因此它为空,因此出现错误。

相反,在您的 ConfigureCreateModel() 方法中,填充 PracticeList 属性(就像您对 PatientList 所做的那样)并删除 ViewData 的使用,并在视图中使用

@Html.DropDownListFor(model => model.PracticeId, Model.PracticeList, ...)

因此您与模型的绑定非常紧密,当您提交表单时,PracticeId 的值将是所选实践的值。

旁注:您需要将脚本更改为 $("#PracticeId").change(function () { ...