mvc 提交后 ActionResult 方法中没有数据

mvc No data in ActionResult method after submit

我有一个索引页面,其中有一个部分用于写项目名称,select 从下拉列表中写项目类型。

在其下方我有一个提交按钮,它指向项目控制器中的 ActionResult 方法 Create。

代码: [更新] index.cshtml:

@using reqcoll.ViewModels
@model myViewModel

@{
  ViewBag.Title = "ReqColl - project";
}

@* First half *@
@using (Html.BeginForm("CreateProject", "Projects"))
{
  @Html.AntiForgeryToken()

  <div class="top-spacing col-md-12 col-lg-12 col-sm-12">
    @RenderTopHalf(Model.modelProject)
  </div>
}


@* Second half *@
@using (Html.BeginForm("CreateRequirement", "Projects"))
{
  @Html.AntiForgeryToken()

  <div class="form-group" id="pnSecondHalf">
    @* Requirements list *@
    <div class=" col-md-6 col-lg-6 col-sm-12">
      @RenderBottomLeftHalf(Model.modelRequirement)
    </div>

    @* New/Edit requirements panel *@
    <div class="col-md-6 col-lg-6 col-sm-12">
      @RenderBottomRightHalf(Model.modelRequirement)
    </div>
  </div>
}

@*     ================================================================================= ============= *@
@* Helpers *@

@helper RenderTopHalf(reqcoll.Models.Project project)
    {
  <div class=" well">
    @Html.ValidationSummary(true, "", new { @class = "text-danger" })
    <div class="row">
      @Html.LabelFor(model => project.projectName, htmlAttributes: new { @class =     "control-label col-md-2 col-lg-2 col-sm-12" })
      <div class="col-md-10 col-lg-10 col-sm-12">
        @Html.TextBoxFor(model => project.projectName, htmlAttributes: new {   @class = "ProjectNameInput" })
        @Html.ValidationMessageFor(model => project.projectName)
      </div>
    </div>
    @Html.ValidationSummary(true, "", new { @class = "text-danger" })
    <div class="row row-spacing">
      @Html.LabelFor(model => project.projectType, htmlAttributes: new { @class = "control-label col-md-2 col-lg-2 col-sm-12" })
      <div class="col-md-10 col-lg-10 col-sm-12">
        @Html.DropDownListFor(model => project.projectType, new SelectList(
              new List<Object>{
                       new { value = 0 , text = "...Select..." },
                       new { value = 1 , text = "Windows application" },
                       new { value = 2 , text = "Web application" },
                       new { value = 3 , text = "Device application"}
                },
              "value",
              "text",
               project.projectType), htmlAttributes: new { @class =    "DropDownList" })
        @Html.ValidationMessageFor(model => project.projectType)
      </div>
      <input type="hidden" value="" id="hdProjectID" />
    </div>
    <div class="row top-spacing col-md-offset-5 col-sm-offset-5">
      <div id="pnCreate" class=" col-sm-4 col-md-4 col-lg-4">
        <input type="submit" class="btn btn-default" value="Create" />
      </div>
      <div id="pnEdit" class=" col-sm-4 col-md-4 col-lg-4">
        <input type="submit" class="btn btn-default" value="Edit" />
        |
        <input type="submit" class="btn btn-default" value="Delete" />
      </div>
    </div>
  </div>
}

@helper RenderBottomLeftHalf(reqcoll.Models.Requirement requirement)
    {
  <div class=" well">
    <table class="table">
      <tr>
        <th>
          @if (Model.modelProject.Requirements != null)
          {
            var m = Model.modelProject;
            if (m.Requirements.Count > 0)
            {
              @Html.DisplayNameFor(model =>  model.modelProject.Requirements[0].shortDesc)
            }
          }
          else
          {
            <label class="label label-primary col-sm-12 col-md-6 col-lg-6">No requirements available</label>
          }
        </th>
        <th></th>
      </tr>
      @if (Model.modelProject.Requirements != null)
      {
        var m = Model.modelProject;
        if (m.Requirements.Count > 0)
        {
          foreach (var item in Model.modelProject.Requirements)
          {
            <tr>
              <td>
                @Html.DisplayFor(modelItem => item.shortDesc)
              </td>
              <td>

                @* buttons here*@

                @*@Html.ActionLink("E", "Edit", new { id = item.requirementID })     |
                  @Html.ActionLink("D", "Delete", new { id = item.requirementID     })*@
              </td>
            </tr>
          }
        }
      }
    </table>
  </div>
}



 @helper RenderBottomRightHalf(reqcoll.Models.Requirement requirement)
    {
  <div class=" well">
    @Html.ValidationSummary(true)
    <div class="row">
      @Html.LabelFor(model => requirement.shortDesc, htmlAttributes: new { @class = "control-label col-md-4 col-lg-4 col-sm-12" })
      <div class="col-md-8 col-lg-8 col-sm-12">
        @Html.TextBoxFor(model => requirement.shortDesc, htmlAttributes: new { @class = "RequirementShortDesc" })
        @Html.ValidationMessageFor(model => requirement.shortDesc)
      </div>
    </div>
    @Html.ValidationSummary(true)
    <div class="row row-spacing">
      @Html.LabelFor(model => requirement.longDesc, htmlAttributes: new { @class = "control-label col-md-4 col-lg-4 col-sm-12" })
      <div class="col-md-8 col-lg-8 col-sm-12 RequirementLongDesc">
        @Html.EditorFor(model => requirement.longDesc)
        @Html.ValidationMessageFor(model => requirement.longDesc)
      </div>
    </div>
    @Html.ValidationSummary(true)
    <div class="row row-spacing">
      @Html.LabelFor(model => requirement.priorityCode, htmlAttributes: new { @class = "control-label col-md-4 col-lg-4 col-sm-12" })
      <div class="col-md-8 col-lg-8 col-sm-12">

        @foreach (var value in Enum.GetValues(requirement.priorityCode.GetType()))
        {
          <div class="control-label col-sm-5 col-md-5 col-lg-5">
            @Html.RadioButtonFor(m => requirement.priorityCode, value)
            @Html.Label(value.ToString())
          </div>
        }


        @Html.ValidationMessageFor(model => requirement.priorityCode)
      </div>
    </div>
    <input type="hidden" value="" id="hdRequirementID" />

    <div class="row top-spacing col-md-offset-5 col-sm-offset-5">
      <div id="pnReqCreate" class=" col-sm-12 col-md-6 col-lg-6">

        @* submit button here *@
        @*@Html.ActionLink("Add", "Add", "Requirement", new { @class = "btn btn-default btnSize" })*@
      </div>
      <div id="pnReqEdit" class=" col-sm-12 col-md-6 col-lg-6">
        @* submit buttons here *@
        @*@Html.ActionLink("Edit", "Edit", "Requirement", new { @class = "btn btn-default btnSize" })
          @Html.ActionLink("Delete", "Delete", "Requirement", new { @class = "btn btn-default btnSize" })*@
      </div>
    </div>
  </div>
}





@section Scripts {
  <script>

    $(function () {

      var pID = $('#hdProjectID').val();

      if (pID != null) {
        if (pID.length > 0) {
          $('#pnEdit').show();
          $('#pnCreate').hide();
          $('#pnSecondHalf').show();
        } else {
          $('#pnEdit').hide();
          $('#pnCreate').show();
          $('#pnSecondHalf').hide();
        }
      } else {
        $('#pnEdit').hide();
        $('#pnCreate').show();
        $('#pnSecondHalf').hide();
      }

      var rID = $('#hdRequirementID').val();

      if (rID != null) {
        if (rID.length > 0) {
          $('#pnReqEdit').show();
          $('#pnReqCreate').hide();
        } else {
          $('#pnReqEdit').hide();
          $('#pnReqCreate').show();
        }
      } else {
        $('#pnReqEdit').hide();
        $('#pnReqCreate').show();
      }

    });

  </script>

  @Scripts.Render("~/bundles/jqueryval")
}

视图模型:

using reqcoll.Models;

namespace reqcoll.ViewModels
{
  public class myViewModel
  {
    public Project modelProject;
    public Requirement modelRequirement;

  }
}

控制器:

using System.Web.Mvc;
using reqcoll.Models;
using reqcoll.ViewModels;

namespace reqcoll.Controllers
{
  public class ProjectsController : Controller
  {
    private myContext db = new myContext();

    // GET: Projects
    public ActionResult Index()
    {
      // allow more than one model to be used in the view

      var vm = new myViewModel()
      {
        modelProject = new Project() { projectName = "test", projectType = 1 },
        modelRequirement = new Requirement() { requirementID = -1 },
      };

      return View(vm);
    }


    [HttpPost]
    [ValidateAntiForgeryToken]
    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult CreateProject(myViewModel vm)
    {
      if (vm != null)
      {
        var ab = Request.Form;

        // key 1: __RequestVerificationToken
        // key 2: project.projectName
        // key 3: project.projectType


        if (ModelState.IsValid)
        {
          Project project = vm.modelProject;

          // db.Project.Add(project.Item1);
          //  db.SaveChanges();
          // return RedirectToAction("Index");
        }
      }
      return RedirectToAction("Index");
    }

    protected override void Dispose(bool disposing)
    {
      if (disposing)
      {
        db.Dispose();
      }
      base.Dispose(disposing);
    }

  }
}

[原创]

@using (Html.BeginForm("Create", "Projects"))
{
  @Html.AntiForgeryToken()

  <div class="top-spacing col-md-12 col-lg-12 col-sm-12">
    <div class=" well">
      @Html.ValidationSummary(true)
      <div class="row">
        @Html.LabelFor(model => model.Item1.projectName, htmlAttributes: new { @class = "control-label col-md-2 col-lg-2 col-sm-12" })
        <div class="col-md-10 col-lg-10 col-sm-12">
          @Html.TextBoxFor(model => model.Item1.projectName, htmlAttributes: new { @class = "ProjectNameInput" })
          @Html.ValidationMessageFor(model => model.Item1.projectName)
        </div>
      </div>
      @Html.ValidationSummary(true)
      <div class="row row-spacing">
        @Html.LabelFor(model => model.Item1.projectType, htmlAttributes: new { @class = "control-label col-md-2 col-lg-2 col-sm-12" })
        <div class="col-md-10 col-lg-10 col-sm-12">
          @Html.DropDownListFor(model => model.Item1.projectType, new  SelectList(
              new List<Object>{
                       new { value = 0 , text = "...Select..."  },
                       new { value = 1 , text = "Windows application"  },
                       new { value = 2 , text = "Web application" },
                       new { value = 3 , text = "Device application"}
                },
              "value",
              "text",
               0), htmlAttributes: new { @class = "DropDownList" })
          @Html.ValidationMessageFor(model => model.Item1.projectType)
        </div>
        <input type="hidden" value="" id="hdProjectID" />
      </div>
      <div class="row top-spacing col-md-offset-5 col-sm-offset-5">
        <div id="pnCreate" class=" col-sm-4 col-md-4 col-lg-4">
          <input type="submit" class="btn btn-default" value="Create" />
        </div>
        <div id="pnEdit" class=" col-sm-4 col-md-4 col-lg-4">

          <input type="submit" class="btn btn-default" value="Edit" />
          |
          <input type="submit" class="btn btn-default" value="Delete" />
        </div>
      </div>
    </div>
  </div>
}

项目控制器:

 private myContext db = new myContext();

 // GET: Projects
 public ActionResult Index()
 {
   // allow more than one model to be used in the view
   return View(new Tuple<Project, Requirement, Priority>(new Project(), new Requirement(), new Priority()));
 }

 [HttpPost]
 [ValidateAntiForgeryToken]
 [AcceptVerbs(HttpVerbs.Post)]
 public ActionResult Create([Bind(Include = "projectName,projectType")] Project project)
 {
   if (ModelState.IsValid)
   {
     db.Project.Add(project);
     db.SaveChanges();
     return RedirectToAction("Index");
   }

   return RedirectToAction("Index");
 }

所以当提交按钮被点击时,调用了ActionResult Create,但是ModelState是无效的,没有用户输入的信息。

我做错了什么?

您的模型看起来像复杂对象,因为您正在使用模型。Item1.projectName 和模型。Item1.projectType,但在操作方法中您试图直接获取值,这是错误的。

[更新代码]

随着新代码的发布,对您的模型的这种快速更正将允许它从您的角度正确绑定:

namespace reqcoll.ViewModels
{
  public class myViewModel
  {
    public Project project;
    public Requirement requirement;

  }
}

[原创]

尽管使用 Tuple<> 类型而不是定义 class 来封装要传递给视图的数据。您仍然可以通过在您的视图中创建一个助手来实现您想要的。

@helper RenderMyProject(Project project) {
    ...
    @Html.TextBoxFor(x=> project.projectType)
    ...
}

然后,你会调用这个助手

@RenderMyProject(model.Item1)

有什么区别?

输入的名称将会改变。而不是将 [Item1.projectType] 在响应对象内部发布到您的控制器,它看起来像 [project.projectType],它将自动映射到您的项目参数。

找到问题了。

我添加了{get;将 myViewModel 中的 set;} 设置到两个模型,然后它就起作用了。

所以:

using reqcoll.Models;

namespace reqcoll.ViewModels
{
  public class myViewModel
  {
    public Project Project { get; set; }
    public Requirement Requirement { get; set; }

  }
}