C# ViewModel在action方法中获取空值

C# ViewModel在action方法中获取空值,c#,asp.net-mvc,asp.net-mvc-4,C#,Asp.net Mvc,Asp.net Mvc 4,我正在使用ViewModel检索控制器操作中输入的数据。但是ViewModel在其属性中获取空值。我正在创建一个局部视图 在该局部视图中,我通过绑定ViewModel创建了下拉列表,然后在其他视图中渲染该局部视图 下面是我的代码 我的ViewModel: public class LookUpViewModel { RosterManagementEntities rosterManagementContext = new RosterManagementEntities

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

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

下面是我的代码

我的ViewModel:

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; }
当我把调试器放在我的控制器动作方法上时,控制转到那个动作方法。 但ViewModel对象中包含null。 我尝试使用FormCollection对象访问输入的值,并按预期获取所有数据

下面是我使用FormCollection执行控制器操作的代码

 [HttpPost]
        public void AddResource(FormCollection form)
        {
            var x = form["tblStreams"]; //I get value here..
        }
有人能解释一下为什么我不能在ViewModel对象中获取值吗?
谢谢……

这个答案不会直接解决您的问题,但首先,我建议您至少将ViewModel的填充工作外包给控制器(否则每次调用构造函数时它都会重新创建DBContext)。ViewModel应仅包含数据-无逻辑。其次,我会在语句中使用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);
}

您不能将dropdownlist绑定到复杂对象的集合—在您的情况下是
IEnumerable
IEnumerable

标记只回发单个值(所选选项的值),因此在POST方法中,
DefaultModelBinder
尝试这样做
testName.tblCurrentLocations=“1”
(假设所选选项的值为
1
),这当然会失败,并且属性设置为
null

您需要一个包含要绑定到的属性的视图模型(理想情况下包括
DropDownListFor()
帮助程序使用的
SelectList

然后在视图中

@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的回答中所指出的,视图模型应该只包含视图所需的属性。控制器负责填充值。视图模型不应调用数据库-甚至不应知道数据库存在。

您不能将下拉列表绑定到复杂对象的集合(A
仅回发单个值(所选选项的值)。视图模型需要绑定到属性-例如
public int SelectedLocation{get;set;}
和同上,对于所选的流,您希望发生什么,您想要什么值,该视图模型的编码方式每次使用时都会转到您的数据存储区,只需选择
tblCurrentLocations
和“tblStreams”。此外,您还可以通过下拉菜单将所选值分配给您在中填充的相同列表电子视图模型constructor@StephenMuecke你能用一些代码解释我吗?哦,谢谢你解释我不应该在ViewModelYou添加逻辑,可能会考虑引入工厂来创建你的VIEWMDES,这使得你的控制器变得更加干净。请看这里:完美!它工作了…谢谢史蒂芬,你有任何文档吗?n这将帮助我理解这个主题?你指的是哪个主题?不用担心…花了一些时间阅读你的代码。这是不言自明的。不需要阅读文档
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);
}
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
}