对象引用未设置DropDownListFor

时间:2015-04-21 02:16:49

标签: c# asp.net-mvc asp.net-mvc-4

我还在学习MVC并感到困惑。我正在将带有数据库的CRUD的Windows应用程序转换为MVC网站。我得到了一个完整的ViewModel的CRUD工作,它已经使用了dropdownlist并且代码是相同的但是抛出对象引用而不是在另一个页面中设置错误。

控制器

public ActionResult Create()
{
    var shiftsEmployees = new ShiftsEmployeesViewModel();

    var oEmployees = new CEmployees();
    oEmployees.GetActiveEmployees();

    shiftsEmployees.Employees = oEmployees;

    return View(shiftsEmployees);
}

// POST: Shifts/Create
[HttpPost]
public ActionResult Create(ShiftsEmployeesViewModel shiftsEmployees)
{
    try
    {
        shiftsEmployees.InsertShift();
        return RedirectToAction("Index");
    }
    catch
    {
        return View();
    }
}

查看

@model StatTracker.ASPMVC.ViewModels.ShiftsEmployeesViewModel

@{
ViewBag.Title = "Add Shift";
Layout = "~/Views/Shared/_Layout.cshtml";
}

@using (Html.BeginForm())
{
@Html.AntiForgeryToken()
<div class="form-horizontal text-center">
    @Html.ValidationSummary(true, "", new {@class = "text-danger"})

    <div class="form-group">
        <div class="input-group date col-md-12">
            @Html.LabelFor(model => model.Shift.Date, new {@class = "control-label"})&nbsp;
            @Html.EditorFor(model => model.Shift.Date, new {@class = "form-control datepicker", placeholder = "Pick a date"})
            @Html.ValidationMessageFor(model => model.Shift.Date, "", new {@class = "text-danger"})

            @Html.LabelFor(model => model.Employee.FullName, new {@class = "control-label"})&nbsp;
            @Html.DropDownListFor(model => model.Employee.Id, new SelectList(Model.Employees.Employees, "Id", "FullName", Model.Employee), null, null)
            @Html.ValidationMessageFor(model => model.Employee.Id, "", new {@class = "text-danger"})

            @Html.LabelFor(model => model.Shift.Hours, new {@class = "control-label"})&nbsp;
            @Html.EditorFor(model => model.Shift.Hours, new {@class = "form-control", placeholder = "Hours worked"})
            @Html.ValidationMessageFor(model => model.Shift.Hours, "", new {@class = "text-danger"})
        </div>
    </div>

    <div class="form-group">
        <div class="col-md-12">
            <input type="submit" value="Add Shift" class="btn btn-default"/>
        </div>
    </div>
</div>
}
<div class="text-center col-md-12">
      @Html.ActionLink("Back to List", "Index")
</div>

视图模型:

namespace StatTracker.ASPMVC.ViewModels
{
    public class ShiftsEmployeesViewModel
    {
        public CShift Shift { get; set; }
        public CEmployee Employee { get; set; }
        public CEmployees Employees { get; set; }

        public void InsertShift()
        {
            CShift.InsertShift(hours: Shift.Hours, employeeid: Employee.Id, date: Shift.Date);
        }

        public void UpdateShift()
        {
            CShift.UpdateShift(hours: Shift.Hours, employeeid: Employee.Id, date: Shift.Date, shiftid: Shift.Id);
        }
    }
}

具有相同想法的工作代码 控制器

 public ActionResult Create()
    {
        var oSalesEmployeeService = new SalesEmployeeServiceViewModel();

        var oServices = new CServices();
        oServices.GetServices();

        var oEmployees = new CEmployees();
        oEmployees.GetActiveEmployees();

        oSalesEmployeeService.Employees = oEmployees;
        oSalesEmployeeService.Services = oServices;

        return View(oSalesEmployeeService);
    }

    // POST: Sales/Create
    [HttpPost]
    public ActionResult Create(SalesEmployeeServiceViewModel oSalesEmployeeService)
    {
        try
        {
            oSalesEmployeeService.InsertSale();
            return RedirectToAction("Index");
        }
        catch
        {
            return View();
        }
    }

视图模型

using StatTracker.BL;

namespace StatTracker.ASPMVC.ViewModels
{
public class SalesEmployeeServiceViewModel
{
    public CSale Sale { get; set; }
    public CEmployees Employees { get; set; }
    public CServices Services { get; set; }
    public CEmployee Employee { get; set; }
    public CService Service { get; set; }

    public void InsertSale()
    {
        CSale.InsertSale(service: Service.Id, date: Sale.Date, employee: Employee.Id);
    }

    public void UpdateSale()
    {
        CSale.UpdateSale(service: Service.Id, date: Sale.Date, employee: Employee.Id, salesid: Sale.Id);
    }
  }
}

视图

@model StatTracker.ASPMVC.ViewModels.SalesEmployeeServiceViewModel

@{
    ViewBag.Title = "Add Sale";
    Layout = "~/Views/Shared/_Layout.cshtml";
}

@using (Html.BeginForm())
{
@Html.AntiForgeryToken()
<div class="form-horizontal text-center">
    @Html.ValidationSummary(true, "", new {@class = "text-danger"})

    <div class="form-group">
        <div class="input-group date col-md-12">
            @Html.LabelFor(model => model.Sale.Date, new {@class = "control-label"})&nbsp;
            @Html.EditorFor(model => model.Sale.Date, new {@class = "form-control datepicker", placeholder = "Pick a date"})
            @Html.ValidationMessageFor(model => model.Sale.Date, "", new {@class = "text-danger"})

            @Html.LabelFor(model => model.Employee.FullName, new {@class = "control-label"})&nbsp;
            @Html.DropDownListFor(model => model.Employee.Id, new SelectList(Model.Employees.Employees, "Id", "FullName", Model.Employee), null, null)
            @Html.ValidationMessageFor(model => model.Employee.Id, "", new {@class = "text-danger"})

            @Html.LabelFor(model => model.Service.Description, new {@class = "control-label"})&nbsp;
            @Html.DropDownListFor(model => model.Service.Id, new SelectList(Model.Services.Services, "Id", "Description", Model.Service), null, null)
            @Html.ValidationMessageFor(model => model.Service.Id, "", new {@class = "text-danger"})
        </div>
    </div>

    <div class="form-group">
        <div class="col-md-12">
            <input type="submit" value="Add Sale" class="btn btn-default"/>
        </div>
    </div>
</div>
}

<div class="text-center col-md-12">
    @Html.ActionLink("Back to List", "Index")
</div>

2 个答案:

答案 0 :(得分:0)

是的,因为model.Employee尚未初始化,因此,model.Employee.Id将抛出空引用异常。之后你还需要初始化shift对象,因为当访问model.Shift.Hours时它也会抛出一个空引用异常。请参阅下面的建议

您必须初始化剩余的属性

public ActionResult Create()
{
    var oEmployees = new CEmployees();
    oEmployees.GetActiveEmployees();

    var shiftsEmployees = new ShiftsEmployeesViewModel
    {
        Employee = new CEmployee(),
        Shift = new CShift(),
        Employees = oEmployees;
    };

    return View(shiftsEmployees);
}

另一种选择是始终在视图模型的构造函数中初始化它们(您只需确保调用GetActiveEmployees的某个地方)

public class ShiftsEmployeesViewModel
{
    public ShiftsEmployeesViewModel()
    {
        this.oEmployees = new CEmployees();
        this.Employee = new CEmployee();
        this.Shift = new CShift();
    }
 }

同时更改视图中的下拉列表

的实现
@Html.DropDownListFor(model => model.Employee.Id, 
                      new SelectList(Model.Employees.Employees ?? new List<CEmployee>(), 
                                     "Id", 
                                     "FullName"))

答案 1 :(得分:0)

您没有准确指出错误被抛出的位置,但会有很多原因

首先,视图模型不仅仅是一系列数据模型的持有者。它应该只包含您需要在视图中显示/编辑的属性。目前,如果CShiftCEmployee的任何属性具有验证属性(DateHours属性除外),则您的模型将无效。

其次,当您返回视图时,您需要将模型返回到视图,并且还要分配当前为空的Employees值(因此当您访问Model.Employees.Employees时会出现异常DropDownList()方法)。

根据您显示的视图,您的视图模型应该只是(根据需要添加验证属性)

public class ShiftsEmployeesViewModel
{
  public DateTime Date { get; set; }
  public int Employee { get; set; }
  public float Hours { get; set; }
  public SelectList EmployeeList { get; set; }
}

控制器

public ActionResult Create()
{
  ShiftsEmployeesViewModel model = new ShiftsEmployeesViewModel();
  model.Employee = ? // set default selection
  ConfigureCreateModel(model);
  return View(model);
}

[HttpPost]
public ActionResult Create(ShiftsEmployeesViewModel model)
{
  if (!ModelState.IsValid)
  {
    ConfigureCreateModel(model);
    return View(model);
  }
  .... // map the view model properties to a new instance of the data model, save and redirect
}

private void ConfigureCreateModel(ShiftsEmployeesViewModel model)
{
  var oEmployees = (new CEmployees()).GetActiveEmployees();
  model.EmployeeList = new SelectList(oEmployees, "Id", "FullName");
}

查看

@Html.LabelFor(m => m.Date)
@Html.TextBoxFor(m => m.Date)
@Html.ValidationMessageFor(m => m.Date)

@Html.LabelFor(m => m.Employee)
@Html.DropDownListFor(m => m.Employee, Model.EmployeeList, "-please select-")
@Html.ValidationMessageFor(m => m.Employee)

@Html.LabelFor(m => m.Hours)
@Html.EditorFor(m => m.Hours)
@Html.ValidationMessageFor(m => m.Shift.Hours)

旁注:您使用第4个参数的当前SelectList(Model.Employees.Employees, "Id", "FullName", Model.Employee)用法毫无意义。您绑定到属性,因此尝试设置Selected的值将被忽略(所选选项基于您绑定的属性的值)