如何将 ViewModel 与 DropDownListFor 结合使用

本文关键字:结合 DropDownListFor ViewModel | 更新日期: 2023-09-27 18:31:51

MVC.NET 的新手(通常还有C#...并普遍开发)并尝试围绕视图模型进行思考。我有一个非常基本的要求。我有ActorUseCaseProject实体。要创建一个新UseCase我想要一个视图,其中包含与UseCase位于同一Project DropDownListFor Actors的视图。项目id位于 URL 中。我一直在关注这个 如何将选择列表与视图模型绑定?但是我遇到了一个错误:

DataBinding: 'System.Web.Mvc.SelectListItem' does not contain a property with the name 'ActorId'.

另外,我真的不知道如何在我的POST方法中进行映射 - 我很高兴现在手动执行此操作而无需AutoMapper.

视图模型:

 public class UserGoalsStepViewModel
{
    public enum GoalLevel
    {
        Summary, UserGoal, SubGoal,
    }
        public int ProjectId { get; set; }
        public int ActorId { get; set; }
        public SelectList ActorList { get; set; }
        public string Title { get; set; }
        public GoalLevel Level { get; set; }
        public UserGoalsStepViewModel ()
        {
        }

}

更新: 控制器:已更新以反映以下评论中讨论的更改。

发生了什么事情:1. 在 GET 中创建视图时,模型填充正确(ProjectId、Level 和 ActorList 的值为正确,actorId 为"0",Title 为空。一切都如预期的那样。2.但是在开机自检时,标题设置为"5"(实际上是所选actor的Id,ActorId = 0仍然,级别获得正确的值,ProjectId丢失其值。所以,显然我需要对 SelectList 定义做一些事情,但我不确定为什么 ProjectId 会丢失?

// GET: UseCases/Create
    public ActionResult Create(int id)
    {
        ViewBag.projectId = id;
        //Populate the ViewModel
        UserGoalsStepViewModel model = new UserGoalsStepViewModel()
        {
            ProjectId = id,
            ActorList = new SelectList(db.Actors.Where(a => a.projectID == id), "id", "Title"),
        };
        return View(model);
    }
    // POST: UseCases/Create
    // To protect from overposting attacks, please enable the specific properties you want to bind to, for 
    // more details see http://go.microsoft.com/fwlink/?LinkId=317598.
    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Create([Bind(Include = "ProjectId,ActorId,Title,Level")] UserGoalsStepViewModel model, int id)
    {
        ViewData["Actors"] = new SelectList(db.Actors.Where(a => a.projectID == id), "id", "Title");

        if (ModelState.IsValid)
        {
            //Create a use case object to map to, which can then be saved in the DB
            UseCase uc = new UseCase();
            uc.ProjectID = model.ProjectId;
            uc.ActorID = model.ActorId;
            uc.Level = (Level)model.Level;
            db.SaveChanges();
            return RedirectToAction("Index", new { id = model.ProjectId });
        }
        return View(model);
    }

视图:

@Html.DropDownListFor(model => model.Title, new SelectList(Model.ActorList, "ActorId", "Title"), new { @class = "form-control" })

如何将 ViewModel 与 DropDownListFor 结合使用

尝试:

@Html.DropDownListFor(model => model.Title, Model.ActorList, new { @class = "form-control" })

而不是:

@Html.DropDownListFor(model => model.Title, new SelectList(Model.ActorList, "ActorId", "Title"), new { @class = "form-control" }

问题是您尝试在 DropDownListFor 中创建Selectlist,但Model.ActorList已经是一个SelectList .

代码中可能存在其他问题,但这应该可以让您克服该特定错误。

更新

您 POST 到的控制器方法应如下所示:

public ActionResult Create(UserGoalsStepViewModel model)
{
    // what are we updating? assume it's a project
    var p = from db.Projects.Where(x => x.Id == model.id;
    p.SomeProperty = model.SomeProperty;
    db.SaveChanges();
}

注意 - 为了简洁起见,我删除了一些额外的检查 - obv您需要添加绑定限制、模型状态检查、空检查等。

更新 2

当您发布数据时,Title=5因为标题控件是您的选择列表,而 5 是所选值。 ActorId = 0因为您可能没有保存此值的表单控件,所以 ProjectId 也是如此?如果不看到视图代码,就无法确定。

这是我在帖子中所做的....将发布方法添加到 VM。

public class UserGoalsStepViewModel{  
  // in the ctor initiailze properites...
  public string SelectedValue {get;set;}
  public IEnumerable<SelectListItem> DDL {get;set;}
public void Post(){
    DoSomethingWith(SelectedValue)
}

这需要在视图中使用强类型绑定进行正确的绑定...

@model UserGoalStepViewModel
@Html.DropDownListFor(x=>model.SelectedValue, model.DDL)

控制器(开机自检的操作方法)

[HttpPost]
public ActionResult(UserGoalsStepViewMdoel vm){
      if(ModelState.IsValid){
             vm.Post();
             ModelState.Clear(); // if you want to show changed properties in view.
       }
       return View(vm);
}

最后一件事,确保你想要回发到控制器的所有内容都在 BeginForm 中......MVC 有这样一个习惯,就是只给你回发到强类型控制器操作方法的内容,如果你在 BeginForm 中没有得到每一个,它看起来像"丢失的数据"......