0

我有一个用 Razor 编写的下拉列表,用于我正在开发的 MVC 应用程序:

@Html.DropDownList("BillId", "")

但是,用户不必根据我的程序逻辑选择任何内容(列表中填充了我的控制器中的“Bill”对象)。如果他们没有选择任何东西,我会收到错误

The ViewData item that has the key 'BillId' is of type 'System.Int32' but must be of type 'IEnumerable<SelectListItem>'.

如果未选择任何内容,如何在 Razor 中编写语句以返回 0 的 BillId?

我不确定语法,因为我有纯 Java 和 VB 的背景,但有些类似

 If DropdownBox.SelectedIndex = 0
 Else 
 BillId = DropdownBox.SelectedIndex
 End

控制器如下:

Function Create(id As Integer) As ViewResult
        ViewBag.id = id
        Dim job As Job = New Job
        job.CustomerId = id
        job.JobAmount = 0
        job.JobDate = Date.Now()
        job.JobStatus = "Active"

        Dim BillList = New List(Of Bill)()

        Dim BillQuery = From s In db.Bills
                        Select s

        BillList.AddRange(BillQuery)

        ViewBag.BillIdList = New SelectList(BillList, "BillId", "BillDate")

        ViewBag.BillId = New SelectList(BillList, "BillId", "BillDate")

        Return View(job)
    End Function

create 的 POST 函数如下:

    <HttpPost()>
    Function Create(job As Job) As ActionResult
        If ModelState.IsValid Then
            db.Jobs.Add(job)
            db.SaveChanges()

            Dim customer As Customer = db.Customers.Find(job.CustomerId)
            Dim customerNumber As String = customer.CustCellphone.ToString()
            Dim messageSender As SendMessage = New SendMessage
            Dim smsMessage As String = "LAUNDRY: Job Number " & job.JobId & " has been booked in. You will be notified when individual services within it are ready for collection."
            messageSender.SendMessage(smsMessage, customerNumber)

            Dim url As String = "/RequestedService/AddService/" + job.JobId.ToString()
            Return Redirect(url)
        End If
        Return View(job)
    End Function

编辑

我也想知道这是如何传回的,因为在 POST 中我可以检查“null”?但是我觉得问题可能出在按下提交按钮的那一刻

4

1 回答 1

1

在您的 POST 控制器操作中,您忘记在返回视图之前填充 ViewCrap(哎呀,我的意思是 ViewBag):

<HttpPost()>
Function Create(job As Job) As ActionResult
    If ModelState.IsValid Then
        ...
    End If

    ' Here you must populate the ViewCrap before returning the view the same 
    ' way you did in your GET action because your view depend on it
    Dim BillQuery = From s In db.Bills
                    Select s
    ViewBag.BillId = New SelectList(BillQuery.ToList(), "BillId", "BillDate")

    Return View(job)
End Function

但我强烈建议您使用视图模型并忘记......(我不想发音的词)的存在。


更新:

现在让我们看看实现这一点的正确方法(即使用视图模型)。视图模型是您应该为每个视图定义的类,它将代表其特定要求。因此,从您在评论部分所说的内容到我的回答,您希望在您的视图中有一个下拉列表,用户必须从下拉列表中选择账单,这是必需的。

所以让我们滚动视图模型:

public class JobViewModel
{
    [Required(ErrorMessage = "Please select a bill")]
    [Display(Name = "Bill")]
    public int? SelectedBillId { get; set; }
    public IEnumerable<SelectListItem> Bills 
    { 
        get 
        {
            return db.Bills.ToList().Select(x => new SelectListItem
            {
                Value = x.BillId.ToString(),
                Text = x.BillDate.ToString()
            });
        } 
    }

    public int CustomerId { get; set; }

    ... here you could put any other properties that you want 
        to display on the view, things like JobId, ...
}

然后我们用 2 个动作定义我们的控制器:

public ActionResult Create(int id)
{
    var model = new JobViewModel
    {
        CustomerId = id
    };
    return View(model);
}

[HttpPost]
public ActionResult Create(JobViewModel model)
{
    if (ModelState.IsValid)
    {
        // Using AutoMapper here to map between the domain model
        // and the view model (http://automapper.org/)
        var job = Mapper.Map<JobViewModel, Job>(model);

        // Now call your service layer to do the necessary processings
        // on this job domain model including saving the job and sending 
        // messages and stuff. This avoids polluting your controller with
        // business logic code which belongs to your service layer
        ServiceLayer.ProcessJob(job);

        return RedirectToAction("AddService", "RequestedService", new { id = job.JobId });
    } 

    return View(model);
}

最后,您将拥有一个相应的视图,该视图将被强类型化到视图模型:

@model JobViewModel

@using (Html.BeginForm())
{
    <div>
        @Html.LabelFor(x => x.SelectedBillId)
        @Html.DropDownListFor(x => x.SelectedBillId, Model.Bills, "-- select --")
        @Html.ValidationMessageFor(x => x.SelectedBillId)
    </div>

    ... some other input fields

    <p><button type="submit">OK</button></p>
}

现在,正如评论部分所承诺的,让我展示我所谓的绝对色情方法来解决这个问题,如果你在你的应用程序中实现,我将不得不要求你不再回来询问任何与 ASP.NET MVC 相关的问题在 StackOverflow 上:-)

色情方法包括手动将id = 0 和 text = 空字符串的项目插入列表的开头,然后在控制器内部验证所选 id 是否等于 0,以检查模型是否有效:

因此,在您的 GET 操作中:

Function Create(id As Integer) As ViewResult
    ViewBag.id = id
    Dim job As Job = New Job
    job.CustomerId = id
    job.JobAmount = 0
    job.JobDate = Date.Now()
    job.JobStatus = "Active"

    Dim Bills = db.Bills.ToList().Select(Function(s) New SelectListItem With { .Value = s.BillId.ToString(), .Text = s.BillDate.ToString() })
    Bills.Insert(0, New SelectListItem With { .Value = "0", .Text = "" })
    ViewBag.BillId = Bills

    Return View(job)
End Function

<HttpPost()>
Function Create(job As Job, BillId as Integer) As ActionResult
    If BillId > 0 Then
        db.Jobs.Add(job)
        db.SaveChanges()

        Dim customer As Customer = db.Customers.Find(job.CustomerId)
        Dim customerNumber As String = customer.CustCellphone.ToString()
        Dim messageSender As SendMessage = New SendMessage
        Dim smsMessage As String = "LAUNDRY: Job Number " & job.JobId & " has been booked in. You will be notified when individual services within it are ready for collection."
        messageSender.SendMessage(smsMessage, customerNumber)

        Dim url As String = "/RequestedService/AddService/" + job.JobId.ToString()
        Return Redirect(url)
    End If
    ModelState.AddModelError("BillId", "Please select a bill")
    Return View(job)
End Function

在视图内部:

@Html.DropDownList("BillId")
于 2012-08-21T20:00:18.353 回答