我的观点是没有返回下拉列表信息

时间:2013-10-04 19:17:33

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

我正在运行Visual Studio 2012调试器,并且发现我的productViewModelList参数不包含我希望我的视图传递给我的[HTTPPOST] Edit操作的所有值。我不明白为什么。请参阅下面代码示例中的注释,了解我插入断点的位置,并检查了productViewModelList的值。

为productViewModelList提供以下值:

  

BrandId = 0,   BrandName =“6”,   BrandSelectListItem = null,   ID = 5,   名字=“拐杖”,   价格= 10.0

  • BrandID不正确,在我的DropDownList视图中,我分配了“Catatonics Inc.”其ID为6,我在我的数据库中验证过。
  • BrandName显示“6”,应该是BrandID,BrandName应该是“Catatonics Inc.”。
  • BrandSelectList项是SelectListItem类型的对象,它包含进入我视图中DropDownList项的值。 DropDownList正确显示值,但当我的[httpPost]编辑操作执行时,BrandSelectList为null。我需要访问DropDownList的Selected项目。
  • 所有其他值,ID,名称和价格都是正确的。

以下是我的代码中的一些类。

MedicalProductController

public class MedicalProductController : Controller
{
    private MvcMedicalStoreDb _db = new MvcMedicalStoreDb();

    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Edit(IEnumerable<MedicalProductViewModel> productViewModelList)
    {
        // I have a breakpoint inserted here, and check productViewModelList with debugger.  

        var modelList = GetMedicalProductList(productViewModelList);
        if (ModelState.IsValid)
        {
            foreach (var model in modelList)
                _db.Entry(model).State = EntityState.Modified;

            _db.SaveChanges();
            return RedirectToAction("Index");
        }

        return View(productViewModelList);
    }
}

MedicalProductMapper

public class MedicalProductMapper
{

    public IEnumerable<MedicalProductViewModel> MapMedicalProductViewModel(IEnumerable<MedicalProduct> productList, IEnumerable<Brand> brandList)
    {
        var brandSelectListItem = brandList.Select(b => new SelectListItem()
                                                {
                                                    Text = b.Name,
                                                    Value = b.ID.ToString()
                                                });

        var viewModelList = productList.Select(p => new MedicalProductViewModel() 
                                {
                                    BrandID = p.BrandID,
                                    BrandName = brandList.SingleOrDefault(b => b.ID == p.BrandID).Name,
                                    BrandSelectListItem = brandSelectListItem,
                                    ID = p.ID,
                                    Price = p.Price,
                                    Name = p.Name
                                });

        return viewModelList;
    }

    public IEnumerable<MedicalProduct> MapMedicalProductList(IEnumerable<MedicalProductViewModel> viewModelList)
    {
        var modelList = viewModelList.ToArray().Select( viewModel => new MedicalProduct()
        {
            Name = viewModel.Name,
            Price = viewModel.Price,
            BrandID = Convert.ToInt32(viewModel.BrandSelectListItem.Select(b => b.Value.ToString()))
        });

        return modelList;
    }
}

EDIT.cshtml

@model IEnumerable<MvcMedicalStore.Models.MedicalProductViewModel>

@{
    ViewBag.Title = "Edit";
}

<h2>Edit</h2>

@using (Html.BeginForm()) {
    @Html.AntiForgeryToken()
    @Html.ValidationSummary(true)

    <fieldset>
        <legend>MedicalProduct</legend>
        @Html.EditorFor(m => m)        
        <p>
            <input type="submit" value="Save" />
        </p>
    </fieldset>
}

<div>
    @Html.ActionLink("Back to List", "Index")
</div>

@section Scripts {
    @Scripts.Render("~/bundles/jqueryval")
}

EditorTemplates / MedicalProductViewModel.cshtml

(这是在Edit.cshtml目录的子目录中。)

@model MvcMedicalStore.Models.MedicalProductViewModel

@Html.HiddenFor(item => Model.ID)

<div class="editor-label">
    @Html.LabelFor(item => Model.Name)
</div>
<div class="editor-field">
    @Html.EditorFor(item => Model.Name)
    @Html.ValidationMessageFor(item => Model.Name)
</div>

<div class="editor-label">
    @Html.LabelFor(item => Model.Price)
</div>
<div class="editor-field">
    @Html.EditorFor(item => Model.Price)
    @Html.ValidationMessageFor(item => Model.Price)
</div>

<div class="editor-label">
    @Html.LabelFor(item => Model.BrandName)
</div>
<div class="editor-field">
    @Html.DropDownListFor(item => Model.BrandName, Model.BrandSelectListItem)
    @Html.ValidationMessageFor(item => Model.BrandName)
</div>

编辑:

品牌

public class Brand
{
    [Key]
    public int ID { get; set; }

    [Required]
    [StringLength(30)]
    public string Name { get; set; }
}

MedicalProduct

public class MedicalProduct
{
    [Key]
    public int ID { get; set; }

    [Required]
    [StringLength(50)]
    public string Name { get; set; }

    [Required]
    [DataType(DataType.Currency)]
    public double Price { get; set; }

    // is a foreign key
    public int BrandID { get; set; }
}

MedicalProductViewModel

public class MedicalProductViewModel
{
    [Key]
    public int ID { get; set; }

    [Required]
    [StringLength(50)]
    public string Name { get; set; }

    [Required]
    [DataType(DataType.Currency)]
    public double Price { get; set; }

    public int BrandID { get; set; }

    [DisplayFormat(NullDisplayText="[Generic]")]
    public string BrandName { get; set; }

    public IEnumerable<SelectListItem> BrandSelectListItem { get; set; }
}

1 个答案:

答案 0 :(得分:0)

您没有BrandID的表单元素,因此当模型绑定器将表单POST转换为模型时,它将使用int的默认值,即0. em> do 有BrandName的表单元素:

@Html.DropDownListFor(item => Model.BrandName, Model.BrandSelectListItem)

这可能是(取决于BrandSelectListItem的定义,并基于您描述的观察到的行为)创建select元素,option元素使用可用的BrandName元素BrandID 1}}值作为文本,可用的select值作为值。当HTTP POST中包含BrandID元素时,所选值将是发布的值。因此,您将获得所选的BrandName,但会将其绑定到@Html.DropDownListFor(item => Model.BrandID, Model.BrandSelectListItem) 的值,方法是将其绑定到模型上的该属性。

这听起来像你真正想要的是:

BrandId = 6, BrandName = "", BrandSelectListItem = null, ID = 5, Name = "Crutch", Price = 10.0

然后会给你:

BrandName

您仍然没有BrandName值,但在这种情况下您真的需要一个吗?这是重复的数据。该模型可以动态确定已知BrandID中的BrandName。因此BrandName不需要是模型的读/写属性,它只能是一个只读属性,它根据模型的BrandID获取public string BrandName { get { var brandName = GetBrandName(BrandID); return brandName; } } 。它可能很简单:

GetBrandName

在这种情况下,您将实现BrandID以从数据存储中获取值。或者如果它足够清晰和简洁,那就完成整个事情,这取决于你。您还可以将值缓存在类级别的私有变量中,以便只需要获取一次。 (只需确保清除该变量或在{{1}}更改时随时重新获取它。)

可以保持两个属性不变,但是你要负责确保它们在对象的生命周期内保持同步,包括它在UI中花费的时间。只要您在两个地方记录了相同的信息,您就有责任保持同步。这从来都不好玩。在这种情况下,您需要在视图中使用两个元素(第二个可能是隐藏的表单字段,或者可能是一个样式为隐藏的下拉列表),并且您必须编写一些JavaScript以便随时更新一个另一个改变了。