ASP.NET MVC使用强类型ViewModel将数据从视图保留到控制器

时间:2015-08-06 20:49:54

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

我提前道歉提出之前已经回答的问题,但我仍然是新手,并且发现很难将解决方案应用于我自己的问题。

我有一个视图模型,我在创建时填充一些数据,然后打算使用级联下拉列表填充数据(我不能使用任何客户端脚本)

public class StudentPortalModel
{
    public SelectList LocationListModel { get; set; }
    public SelectList ResidenceListModel { get; set; }
    public int ChosenLocation { get; set; }
    public int ChosenBlock { get; set; }
    public int ChosenFlat { get; set; }
    public int ChosenRoom { get; set; }
    public int ChosenResidence { get; set; }
}

我在控制器中有一个动作,用一些列表填充视图模型,我用它来下载菜单:

[HttpGet]
        public ActionResult SelectResidence()
        {


            List<Location> objLocationList = (from data in db.Locations select data).ToList();
            SelectList objLocationModelData = new SelectList(objLocationList, "LocationId", "LocationName", 0);


            List<Residence> objResidenceList = (from data in db.Residences select data).ToList();
            SelectList objResidenceModelData = new SelectList(objResidenceList, "ResidenceId", "BlockNumber", 0);


            StudentPortalModel objStudentPortalModel = new StudentPortalModel();
            objStudentPortalModel.LocationListModel = objLocationModelData;
            objStudentPortalModel.ResidenceListModel = objResidenceModelData;


            return View(objStudentPortalModel);
        }

我希望发送到视图的模型数据返回到控制器

 @using (Html.BeginForm("SelectLocation", "StudentPortal", FormMethod.Post))
{
    @Html.DropDownListFor(x => x.ChosenLocation, Model.LocationListModel, "---Select Location---")

    <input type="submit" value="Submit"/>
}

我希望在发送回HttpGet方法时保留发布到视图的所有数据。

[HttpPost]
        public ActionResult SelectLocation(StudentPortalModel testPortalInstance)
        {
            List<Location> objLocationList = (from data in db.Locations select data).ToList();
            SelectList objLocationModelData = new SelectList(objLocationList, "LocationId", "LocationName", 0);


            List<Residence> objResidenceList = (from data in db.Residences select data).Where(i => i.LocationId == testPortalInstance.ChosenLocation).DistinctBy(x => x.BlockNumber).ToList();
            SelectList objResidenceModelData = new SelectList(objResidenceList, "ResidenceId", "BlockNumber", 0);

            testPortalInstance.LocationListModel = objLocationModelData;
            testPortalInstance.ResidenceListModel = objResidenceModelData;

            return View("SelectResidence", testPortalInstance);

        }

大家都知道,发回的唯一数据是ChosenLocation,因为当最终用户从下拉列表中选择它时会发回,其他一切都是空的

基本上我需要一种方法来保留用户为每个下拉列表选择的选项。这使我能够缩小用户希望选择的房间,直到我能够从桌子上解密单个房间并将其分配给用户。

我最大的问题是我似乎无法找到我发送给视图的viewmodel数据并将其分配给相同的值以便发回。当我回发到控制器时,一切都是空的,这意味着我必须重新创建数据。

我为我的漫无底道道歉,我把它归结为我一个月只编程的事实。

提前感谢您的帮助!

3 个答案:

答案 0 :(得分:1)

部分观点,应该使用

@Html.RenderChildAction 

您在剃须刀视图中使用的Html Helper上的方法。

你的控制器方法应该用     [ChildActionOnly]

这是一个属性,因此MVC以一种只能通过RenderChildAction调用的方式路由动作,这会阻止人们在浏览器中访问它。

其次,您应该将模型实例传递给级联中每个步骤的视图。

return Partial(theModel);

或     返回部分(&#34; somePartialView&#34;,the Model);

这些返回将是来自控制器Action的示例返回,返回ActionResult类型。

最后,您的表单标记可以将模型传递给回发。 MVC将自动JSON序列化它并且JSON为您反序列化它,因此不需要大量隐藏标记(可能在旧版本的MVC中,但我知道这可以在mvc 4 +中工作)。

以下是部分视图示例:

@model StudentPortalModel
@using (Html.BeginForm("SetSelection", "StudentPortal", new { model = Model}, FormMethod.Post, null))
{
    //Do Form Stuff Here
}

上面注意我将模型作为路径数据对象传递... MVC将序列化为json,将其发布到post数据中,然后控制器将其自动反序列化为模型参数,因为它是一个匿名对象,其模型属性和json类型信息与&#34;模型&#34;的名称相匹配。控制器动作的参数。

示例控制器方法

[HttpPost]
public ActionResult SetSelection(StudentPortalModel model)
{
    return View("NextCascade", Model)
}    

现在,我没有在上面使用ChildAction,因为你希望能够发布到此。 [ChildActionOnly]用于加载部分视图的Action,而不是它回发的动作,那些得到[HttpPost]。

总共有三个属性:

[ChildActionOnly]
[HttpGet]
[HttpPost] 

您可以在同一个操作中同时使用HttpGet和HttpPost,但这是默认设置。换句话说,如果您将所有属性放在一起,它将路由获取和发布请求。如果您只放置HttpGet,它将无法发布请求(您无法发布),等等。

现在,让我们说PartialView被称为StudentSelection:

控制器上应该有一个父操作,它最初在用[ChildActionOnly]修饰的get请求(第一次加载)上返回它。你应该使用@ Html.RenderChildAction来渲染该动作的部分视图。

答案 1 :(得分:1)

Not really clear why you would not want to use javascript/jquery (it would give much better performance) but you will need to pass the selected values to each GET method from the relevant POST method. Assuming the first step is to choose a location, then a residence, your controller methods would be

public ActionResult SelectResidence()
{
  List<Location> locations = (from data in db.Locations select data).ToList();
  StudentPortalModel model = new StudentPortalModel()
  {
    LocationListModel = new SelectList(locations, "LocationId", "LocationName")
  }
  return View(model);
}

Note there is no point generating a SelectList for ResidenceListModel since its not used in the first view which will be

@model StudentPortalModel
@using (Html.BeginForm()) // no need to add parameters
{
  @Html.DropDownListFor(x => x.ChosenLocation, Model.LocationListModel, "---Select Location---")
  <input type="submit" value="Submit"/>
}

which will post back to

[HttpPost]
public ActionResult SelectResidence(StudentPortalModel model)
{
  if (!ModelState.IsValid)
  {
    // repopulate locations and return view
  }
  return RedirectToAction("SelectResidence", new { locationID = model.ChosenLocation });
}

which will redirect to

public ActionResult SelectResidence(int locationID)
{
  List<Residence> residences = (from data in db.Residences select data).Where(i => i.LocationId == locationID).ToList();
  StudentPortalModel model = new StudentPortalModel()
  {
    ChosenLocation = locationID,
    ResidenceListModel = new SelectList(residences, "ResidenceId", "BlockNumber")
  }
  return View(model);
}

whose view will be

@model StudentPortalModel
@using (Html.BeginForm())
{
  @Html.HiddenFor(x => x.ChosenLocation)
  @Html.DropDownListFor(x => x.ChosenResidence, Model.ResidenceListModel , "---Select Residence---")
  <input type="submit" value="Submit"/>
}

which will post back to

public ActionResult SelectResidence(StudentPortalModel model)
{
  if (!ModelState.IsValid)
  {
    // repopulate residences based on the value of model.ChosenLocation and return view
  }
  // your model now contains values for both ChosenLocation and ChosenResidence 
}

Similarly if you then need to go to a view to choose a room you would redirect to (say) public ActionResult SelectResidence(int locationID, int residenceID)

答案 2 :(得分:0)

您在帖子操作中的模型应该包含与您填写的表单中的输入名称匹配的字段。这允许默认的MVC模型绑定将用户选择的值设置为StudentPortalModel中的字段。