【问题标题】:ViewModel getting null values in action methodViewModel 在操作方法中获取空值
【发布时间】:2015-07-23 05:10:04
【问题描述】:

我正在使用 ViewModel 来检索控制器操作中输入的数据。但是 ViewModel 在它的属性中得到了空值。我正在创建一个局部视图

在该局部视图中,我通过绑定 ViewModel 创建 下拉列表,然后在其他 View渲染该局部视图>

下面是我的代码

我的视图模型:

public class LookUpViewModel
    {
        RosterManagementEntities rosterManagementContext = new RosterManagementEntities();
        public  LookUpViewModel()
        {

            tblCurrentLocations = from o in rosterManagementContext.tblCurrentLocations select o;
            tblStreams = from o in rosterManagementContext.tblStreams select o;   
        }

        [Required]
        public virtual IEnumerable<tblCurrentLocation> tblCurrentLocations { get; set; }

 [Required]
        public virtual IEnumerable<tblStream> tblStreams {  get;  set; }

我的部分观点:

@model PITCRoster.ViewModel.LookUpViewModel

@Html.Label("Location")
@Html.DropDownListFor(M=>M.tblCurrentLocations, new SelectList(Model.tblCurrentLocations, "LocationId", "Location"), "Select Location")
@Html.ValidationMessageFor(M=>M.tblCurrentLocations)
<br />
@Html.Label("Stream")

@Html.DropDownListFor(M => M.tblStreams, new SelectList(Model.tblStreams, "StreamId", "Stream"), "Select Streams")
@Html.ValidationMessageFor(M => M.tblStreams)

我在其中渲染此部分视图的视图

@{
    ViewBag.Title = "Resources";
}
<script src="~/Scripts/jquery.validate.min.js"></script>
<script src="~/Scripts/jquery.validate.unobtrusive.min.js"></script>
<h2>Resources</h2>

@using (Html.BeginForm("AddResource", "Resources", FormMethod.Post))
{

    @Html.AntiForgeryToken()
    @Html.ValidationSummary(true)
    Html.RenderPartial("_LookUpDropDowns", new PITCRoster.ViewModel.LookUpViewModel());

    <br />
    <input type="submit" value="Create" />
}

这是我的控制器操作方法: [HttpPost]

public void AddResource(LookUpViewModel testName)
        {
            //code
        }

当我在我的控制器操作方法上放置一个调试器时,控制转到该操作方法。 但是 ViewModel 对象中有 null 。 我尝试使用 FormCollection 对象访问输入的值,并且按预期获取所有数据...

以下是我使用 FormCollection 进行控制器操作的代码

 [HttpPost]
        public void AddResource(FormCollection form)
        {
            var x = form["tblStreams"]; //I get value here..
        }

谁能解释一下为什么我没有在 ViewModel 对象中获取值? 谢谢...

【问题讨论】:

  • 您不能将下拉列表绑定到复杂对象的集合(&lt;select&gt; 仅回发单个值(所选选项的值)。您的视图模型需要绑定属性 - 例如 @ 987654327@ 和所选流的同上
  • 您期望发生什么,您正在寻找什么值,此视图模型的编码方式将在每次使用时转到您的数据存储区,只需选择 tblCurrentLocations 和 'tblStreams' .此外,您的下拉菜单将所选值分配给您在视图模型构造函数中填充的相同列表
  • @StephenMuecke 你能用一些代码解释一下吗?

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


【解决方案1】:

您不能将下拉列表绑定到复杂对象的集合 - 在您的情况下为 IEnumerable&lt;tblCurrentLocation&gt;IEnumerable&lt;tblStream&gt;

&lt;select&gt; 标记仅回发单个值(所选选项的值),因此在 POST 方法中,DefaultModelBinder 试图如此testName.tblCurrentLocations = "1"(假设所选选项的值是1 ) 这当然会失败并且属性设置为null

您需要一个包含要绑定到的属性的视图模型(最好包括 DropDownListFor() 助手使用的 SelectList

public class LookUpViewModel
{
  [Display(Name = "Location")]
  [Required(ErrorMessage = "Please select a location")]
  public int SelectedLocation { get; set; }
  [Display(Name = "Stream")]
  [Required(ErrorMessage = "Please select a stream")]
  public int SelectedStream { get; set; }
  public SelectList LocationList { get; set; }
  public SelectList StreamList { get; set; }
}

然后在视图中

@Html.LabelFor(m => m.SelectedLocation)
@Html.DropDownListFor(m => m.SelectedLocation, Model.LocationList, "-Please select-")
@Html.ValidationMessageFor(m => m.SelectedLocation)

@Html.LabelFor(m => m.SelectedStream)
@Html.DropDownListFor(m => m.SelectedStream, Model.StreamList, "-Please select-")
@Html.ValidationMessageFor(m => m.SelectedStream)

在控制器中

public ActionResult Edit()
{
  LookUpViewModel model = new LookUpViewModel();
  ConfigureViewModel(model);
  return View(model);
}

[HttpPost]
public ActionResult Edit(LookUpViewModel model)
{
  if (!ModelState.IsValid)
  {
    ConfigureViewModel(model);
    return View(model);
  }
  // model.SelectedLocation will contain the value of the selected location
  // save and redirect
}

private void ConfigureViewModel(LookUpViewModel model)
{
  // populate your select lists
  var locations = from o in rosterManagementContext.tblCurrentLocations select o;
  model.LocationList = new SelectList(locations, "LocationId", "Location");
  .... // ditto for streams
}

请注意,Maximilian 的回答中也指出,您的视图模型应该只包含视图所需的属性。您的控制器负责填充这些值。视图模型永远不应该调用数据库——它甚至不应该知道数据库的存在。

【讨论】:

  • 完美!!它有效...谢谢@stephen 你有任何文档可以帮助我理解这个主题吗?
  • 你指的是哪个话题?
  • 不用担心...花一些时间阅读您的代码。这是不言自明的......不需要阅读文档
【解决方案2】:

此答案不会直接解决您的问题,但首先我建议您至少将 ViewModel 的填充外包给控制器(因为否则它会在每次构造函数时重新创建 DBContext叫做)。 ViewModel 应该只包含数据 - 没有逻辑。其次,我会在 Using 语句中使用 DBContext

视图模型:

public class LookUpViewModel
    {    
        [Required]
        public virtual IEnumerable<tblCurrentLocation> tblCurrentLocations { get; set; }

        [Required]
        public virtual IEnumerable<tblStream> tblStreams {  get;  set; }

控制器:

public ActionResult Foo()
{
    LookUpViewModel ViewModel = new LookUpViewModel();
    using(RosterManagementEntities rosterManagementContext = new RosterManagementEntities())
    {
        ViewModel.tblCurrentLocations = from o in rosterManagementContext.tblCurrentLocations select o;
        ViewModel.tblStreams = from o in rosterManagementContext.tblStreams select o; 
    }

    return View(ViewModel);
}

【讨论】:

  • 哦!感谢您解释我不应该在 ViewModel 中添加逻辑
  • 您可能需要考虑引入工厂来创建您的 ViewModel,这会使您的控制器更加简洁。见这里:Simplify Controller logic using factories
猜你喜欢
  • 1970-01-01
  • 2023-03-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-06-20
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多