简体   繁体   English

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

[英]ASP.NET MVC Retaining Data from View to Controller Using Strongly Typed ViewModel

I apologise in advance for asking a question that has been answered before but i am still a novice and find it difficult to apply solutions to my own problem. 我事先向您提出一个已经回答过的问题表示歉意,但是我仍然是一个新手,发现很难对自己的问题应用解决方案。

I have a view model that i populate some data on creating and then intend to fill with data using a cascading drop down list (i cant use any client side scripts) 我有一个视图模型,在创建时会填充一些数据,然后打算使用级联下拉列表填充数据(我不能使用任何客户端脚本)

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; }
}

I have an action in a controller which populates the viewmodel with some lists that i use for drip down menus as so: 我在控制器中有一个操作,该操作使用一些我在下拉菜单中使用的列表填充了视图模型:

[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);
        }

I want the model data sent to the view to be returned back to the controller 我希望将发送到视图的模型数据返回给控制器

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

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

i want all the data i post to the view to be retained when sent back to the HttpGet method. 当发送回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);

        }

As you all probably know, the only data that gets sent back is ChosenLocation as that is sent back when the end user picks it from the drop down list, everything else is empty 大家都知道,唯一发送回的数据是ChosenLocation,因为最终用户从下拉列表中选择该数据时会将其发送回去,其他所有内容均为空

Essentially i need a way of retaining what options the user is choosing for each drop down list. 本质上,我需要一种方法来保留用户为每个下拉列表选择的选项。 This allows me to narrow down what room a user wishes to pick till i am able to decipher a single room from a table and assign it to a user. 这使我可以缩小用户希望选择的房间,直到我能够从表中解密单个房间并将其分配给用户。

My biggest problem is I cant seem to find the viewmodel data I send to the view and assign it to the same value to send back. 我最大的问题是我似乎找不到发送到视图的视图模型数据并将其分配给相同的值以发送回去。 when I post back to the controller everything is empty meaning I have to recreate data. 当我发回控制器时,所有内容都是空的,这意味着我必须重新创建数据。

I apologise for my rambling, I put it down to the fact I have only been programming a month. 我为我的漫漫长途道歉,我将其归结为我仅编程一个月的事实。

Thank you in advance for any help! 预先感谢您的任何帮助!

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. 尚不清楚为什么您不希望使用javascript / jquery(它会提供更好的性能),但是您需要将选定的值从相关的POST方法传递给每个GET方法。 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 注意没有必要为ResidenceListModel生成一个SelectList ,因为它不会在第一个视图中使用

@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) 同样,如果您随后需要查看视图以选择房间,则可以将其重定向到(例如) public ActionResult SelectResidence(int locationID, int residenceID)

Partial views, should make use of 部分观点,应利用

@Html.RenderChildAction 

Which is a method on the Html Helper you use in your razor views. 这是您在剃刀视图中使用的HTML Helper上的一种方法。

Your controller methods should be decorated with [ChildActionOnly] 您的控制器方法应使用[ChildActionOnly]装饰

Which is an attribute that makes it so MVC routes the action in a way where it can only be called via RenderChildAction, which prevents people from going to it's url in their browser. 该属性使MVC能够以只能通过RenderChildAction调用该动作的方式来路由该动作,从而防止人们在其浏览器中访问它的url。

Secondly, you should be passing your models instance to the view on each step of the cascade. 其次,您应该将模型实例传递给级联每一步的视图。

return Partial(theModel);

or return Partial("somePartialView", theModel); 或返回Partial(“ somePartialView”,theModel);

Those returns would be example returns from controller Actions that return an ActionResult type. 这些返回将是返回ActionResult类型的控制器Action的示例返回。

Finally, your form tags can pass your model to the postback. 最后,您的表单标签可以将模型传递给回发。 MVC will automatically JSON serialize it and JSON deserialize it for you, so no need to have tons of hidden tags (maybe in older versions of MVC, but I know this works in mvc 4+). MVC会自动为您进行JSON序列化和JSON反序列化,因此不需要大量隐藏标签(也许在旧版本的MVC中,但我知道这在mvc 4+中有效)。

Here is an example partial view: 这是一个局部视图示例:

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

Notice above I am passing the model as a route data object... MVC will serialize it to json, post it in the post data, then the controller will deserialize it automatically into the model parameter because it's an anonymous object who's model property and json type info matches the name of the "model" parameter on the controller action. 注意,上面我将模型作为路由数据对象进行传递... MVC将其序列化为json,将其发布到post数据中,然后控制器将其自动反序列化为model参数,因为它是一个匿名对象,具有模型属性和json类型信息与控制器操作上“模型”参数的名称匹配。

Example controller method 控制器方法示例

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

Now, I didn't use ChildAction only on the above, because you want to be able to post to this. 现在,我不仅在上面使用ChildAction,因为您希望能够发布到此。 [ChildActionOnly] is for the Action that loads your partial view, not for the action it is posting back to, those get [HttpPost]. [ChildActionOnly]用于加载部分视图的Action,而不适用于将其发布回的操作,这些操作将获得[HttpPost]。

The three attributes in total are: 总共三个属性是:

[ChildActionOnly]
[HttpGet]
[HttpPost] 

You can use both HttpGet and HttpPost on the same action, but that is the default. 您可以在同一操作上使用HttpGet和HttpPost,但这是默认设置。 In other words if you leave off the attributes all together it will route for get and post requests. 换句话说,如果您一起放弃所有属性,它将路由获取和发布请求。 Put if you only put HttpGet it will not route for Post Requests (you can't post to it), etc. 如果仅放置HttpGet,则放置它,它将不会路由到Post Requests(您不能将其发布到)等。

Now, let's say that PartialView is called StudentSelection: 现在,假设PartialView称为StudentSelection:

There should be a parent action on the controller that returns it initially on the get request (first load) decorated with [ChildActionOnly]. 控制器上应有一个父操作,该操作最初在以[ChildActionOnly]装饰的get请求(首次加载)上将其返回。 And you should use @Html.RenderChildAction to render that partial view on that action. 并且您应该使用@ Html.RenderChildAction呈现该操作的局部视图。

Your Model in the post action should have fields that match the input name's in your form that the user fills out. 发布操作中的模型应具有与用户填写的表单中的输入名称相匹配的字段。 That allows the default MVC model binding to set the user's chosen values to the fields in your StudentPortalModel. 这允许默认的MVC模型绑定将用户选择的值设置为StudentPortalModel中的字段。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM