Razor默认为下拉框

时间:2012-08-21 09:42:57

标签: vb.net asp.net-mvc-3 razor

我有一个用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中写一个语句来返回BillId为0?

我不确定语法,因为我在直接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

创建的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'?但是我觉得问题可能是按下提交按钮的时刻

1 个答案:

答案 0 :(得分: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>
}

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

色情方法包括手动将id = 0且text = empty string的项目插入列表的开头,然后在控制器内部验证所选的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")