【问题标题】:Failing to pass data from view to controller after submitting a form in MVC在 MVC 中提交表单后,无法将数据从视图传递到控制器
【发布时间】:2021-08-22 10:30:41
【问题描述】:

在我的项目中,我有电影、电影和放映模型。现在我希望用户能够根据他选择的电影院订购他选择的放映门票。首先,用户将选择一个电影院,然后他将看到可用于他选择的电影院的放映。

使用foreach 方法,我正在遍历所选电影院中可用的放映并将它们显示在表单中,因此用户可以单击“立即订购”按钮提交他选择的特定放映的表单。

在这里你可以看到我的观点:

@model IEnumerable<CinemaProjectMVC.Models.Screening>
@{
    ViewBag.Title = "OrderForm";
    Layout = "~/Views/Shared/_Layout.cshtml";
}

<h2>Buy Tickets</h2>

<table id="screenings" class="table table-bordered table-hover">
    <thead>
        <tr>
            <th>Movie</th>
            <th>Date</th>
            <th>Tickets</th>
            <th>Price</th>
            <th>Order Now!</th>
        </tr>
    </thead>
    <tbody>
        @{
            if (!Model.Any())
            {
                <tr>
                    <td class="empty-table" colspan="5">There are no screenings.</td>
                </tr>
            }
        }
        @foreach (var screening in Model)
        {
            using (Html.BeginForm("Save", "Orders"))
            {
                @Html.ValidationSummary(true, "Please fix the following errors.")
                <tr>

                    <td>@screening.Movie.Name</td>

                    <td>@screening.Date.ToString("d MMM yyyy, HH:mm")</td>

                    <td>
                        @Html.TextBoxFor(s => screening, new { @type = "number", Value = "1" })
                        @Html.ValidationMessageFor(s => screening)
                    </td>
                    <td id="@screening.Price">@screening.Price</td>
                    <td><button type="submit" class="order-now-button">Order Now</button></td>
                </tr>
                @Html.HiddenFor(s => s.Id)
                @Html.AntiForgeryToken()
            }
        }
    </tbody>
</table>

现在,@Html.HiddenFor(s =&gt; s.Id) 行存在问题,可能是因为我使用 IEnumerable 作为模型。如果不传递表单中的 Id,我就无法将其传递给另一个操作。

我尝试将此行更改为 @Html.HiddenFor(s =&gt; screening.Id) 编译,但我仍然没有在“保存”操作中获得所需的数据。

我的行动:

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Save(Screening screening)
{
    return RedirectToAction("", "");
}

现在我的action是空的,但是通过调试我可以看到提交表单后“screening”变量为null。

这是将有关筛查的数据传递到 OrderForm 视图中的表单的操作:

public ActionResult AvailableScreenings(int id)
        {
            var screenings = _context.Screenings.Where(s => s.CinemaId == id).ToList();
            var cinemas = _context.Cinemas.ToList();
            var movies = _context.Movies.ToList();

            var viewModel = new ScreeningFormViewModel
            {
                Cinemas = cinemas,
                Movies = movies,
                Date = DateTime.Now
            };

            return View("OrderForm", screenings);
        }

最后,我将添加我的 Screening 和 ScreeningFormViewModel 模型以防万一 -

筛选模型:

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Web;

namespace CinemaProjectMVC.Models
{
    public class Screening
    {
        public int Id { get; set; }

        public Cinema Cinema { get; set; }

        [Required]
        public byte CinemaId { get; set; }

        public Movie Movie { get; set; }

        [Required]
        public byte MovieId { get; set; }

        [Required]
        public DateTime Date { get; set; }

        [Required]
        [Display(Name = "Available Seats")]
        [ValidNumberOfSeats]
        public int AvailableSeats { get; set; }

        [Required]
        [Range(0, int.MaxValue, ErrorMessage = "Please enter valid number")]
        public int Price { get; set; }

        public Screening() { }

        public Screening(int id, Cinema cinema, Movie movie, byte cinemaId, byte movieId, DateTime date, int availableSeats, int price)
        {
            Id = id;
            Cinema = cinema;
            Movie = movie;
            CinemaId = cinemaId;
            MovieId = movieId;
            Date = date;
            AvailableSeats = availableSeats;
            Price = price;
        }
    }
}

ScreeningFormViewModel:

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using CinemaProjectMVC.Models;
using System.Linq;
using System.Web;

namespace CinemaProjectMVC.ViewModels
{
    public class ScreeningFormViewModel
    {
        public int? Id { get; set; }

        public IEnumerable<Cinema> Cinemas { get; set; }

        [Required]
        [Display(Name = "Cinemas")]
        public byte? CinemaId { get; set; }

        public IEnumerable<Movie> Movies { get; set; }

        [Required]
        [Display(Name = "Movies")]
        public byte? MovieId { get; set; }

        [Required]
        public DateTime Date { get; set; }

        [Required]
        [Display(Name = "Available Seats")]
        public int AvailableSeats { get; set; }

        [Required]
        [Range(0, int.MaxValue, ErrorMessage = "Please enter valid number")]
        public int Price { get; set; }

        public string Title
        {
            get
            {
                return Id != 0 ? "Edit Screening" : "New Screening";
            }
        }

        public ScreeningFormViewModel()
        {
            Id = 0;
        }

        public ScreeningFormViewModel(Screening screening)
        {
            Id = screening.Id;
            CinemaId = screening.CinemaId;
            MovieId = screening.MovieId;
            Date = screening.Date;
            AvailableSeats = screening.AvailableSeats;
            Price = screening.Price;
        }
    }
}

我不确定我的问题出在哪里,也许我没有将正确的模型传递给视图,或者我的表单中可能存在其他问题。

【问题讨论】:

  • 似乎在AvailableScreenings()操作方法中View("OrderForm", screenings);应该用viewModel而不是screenings来调用。
  • 你打算将什么传递给OrderForm 视图-ScreeningFormViewModelIEnumerable&lt;CinemaProjectMVC.Models.Screening&gt; 的实例?
  • 你是对的,在尝试不同的方法时,我忘记从我的代码中删除 viewModel。放映列表是我想要传递给视图的内容,又名 - IEnumerable&lt;CinemaProjectMVC.Models.Screening&gt;
  • 这是什么? @Html.TextBoxFor(s => screenshot, new { @type = "number", Value = "1" }) 你要把整个对象放在文本字段中吗?
  • 不,这个字段是用户想要订购的门票数量,我的模型中没有 Ticket 属性(我发现我不需要)但我有为 TextBoxFor 传递一个 lambda 表达式,传递整个对象对我有用,所以我保持原样。但是我现在可以看到问题了,如何在不将其绑定到模型中的任何属性的情况下创建此文本框?

标签: c# asp.net-mvc forms razor controller


【解决方案1】:

您可以通过将视图代码修改为:

 @for(int i=0;i<Model.Count;i++)
    {
        using (Html.BeginForm("Save", "Orders"))
        {
            @Html.ValidationSummary(true, "Please fix the following errors.")
            <tr>                    
                <td>@Html.DisplayFor(m=>m[i].Movie.Name</td>
                <td>@Html.DisplayFor(m=>m[i].Date.ToString("d MMM yyyy, HH:mm"))</td>

                <td>
                    @Html.TextBoxFor(m =>m[i].screening, new { @type = "number", Value = "1" })
                    @Html.ValidationMessageFor(m =>m[i].screening)
                </td>
                <td>m=>m[i].Price</td>
                <td><button type="submit" class="order-now-button">Order Now</button></td>
            </tr>
            @Html.HiddenFor(m => m[i].Id)
            @Html.AntiForgeryToken()
        }
    }

使用它,您可以通过迭代表单轻松实现您真正想要的,或者我们可以说基于订单的表单。

如果这个答案对你有用,请告诉我。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-05-29
    • 2016-08-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-04-09
    相关资源
    最近更新 更多