简体   繁体   English

我的视图没有返回下拉列表信息

[英]My view isn't returning dropdownlist information

I am running the Visual studio 2012 debugger, and have found that my productViewModelList parameter does not contain all the values I want my view to pass to my [HTTPPOST] Edit action. 我正在运行Visual Studio 2012调试器,并且发现我的productViewModelList参数不包含我希望视图传递给[HTTPPOST] Edit操作的所有值。 I don't understand why. 我不明白为什么。 Please refer to the comment in the code sample below for the location I that I inserted the breakpoint and checked the values of productViewModelList. 请参考以下代码示例中的注释,以获取插入断点并检查productViewModelList值的位置I。

The following values are given to productViewModelList: 以下值被赋予productViewModelList:

BrandId = 0, BrandName = "6", BrandSelectListItem = null, ID = 5, Name = "Crutch", Price = 10.0 BrandId = 0,BrandName =“ 6”,BrandSelectListItem = null,ID = 5,名称=“ Crutch”,价格= 10.0

  • BrandID is incorrect, In the view in my DropDownList, I assign "Catatonics Inc." BrandID错误,在我的DropDownList中的视图中,我分配了“ Catatonics Inc.”。 Which has an ID of 6, Which I verified in my database. ID为6的ID,我已在数据库中对其进行了验证。
  • BrandName is showing "6" which should be in BrandID, BrandName should be "Catatonics Inc." 品牌名称显示“ 6”,该名称应在品牌ID中,品牌名称应为“ Catatonics Inc.”。
  • BrandSelectList item is an object of type SelectListItem, it contains the values that go into The DropDownList item in my view. BrandSelectList项目是SelectListItem类型的对象,它包含进入我的视图中的DropDownList项目的值。 The DropDownList correctly shows the values, but BrandSelectList is null when my [httpPost] edit action executes. DropDownList正确显示值,但是当执行[httpPost]编辑操作时,BrandSelectList为null I need to access the DropDownList's Selected item. 我需要访问DropDownList的Selected项目。
  • all other values, ID, Name, and Price are correct. 所有其他值,ID,名称和价格都是正确的。

Here are some classes in my code. 这是我代码中的一些类。

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 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 EditorTemplates / MedicalProductViewModel.cshtml

(this is in subdirectory of Edit.cshtml's directory.) (位于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>

EDIT: 编辑:

Brand

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

You don't have a form element for BrandID , so when the model binder translates the form POST into a model it's going to use the default value for int , which is 0. You do have a form element for BrandName : 您没有BrandID的表单元素,因此,当模型绑定器将POST表单转换为模型时,它将使用int的默认值int ,该默认值为0。您确实有一个BrandName的表单元素:

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

This is presumably (depending on the definition of BrandSelectListItem , and based on the observed behavior you describe) going to create a select element where the option elements use the available BrandName values as the text and the available BrandID values as the value. 据推测(取决于BrandSelectListItem的定义,并根据您描述的观察到的行为),将创建一个select元素,其中option元素将可用的BrandName值用作文本,而将可用的BrandID值用作值。 When a select element is included in an HTTP POST, the selected value is what is posted. HTTP POST中包含select元素时,所选值即为发布的值。 So you're getting the selected BrandID , but assigning it to the value for BrandName by binding it to that property on the model. 所以,你要选择的BrandID ,但它分配给了价值BrandName通过绑定到模型上的该属性。

It sounds like what you really want is this: 听起来您真正想要的是:

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

This would then give you: 这将为您提供:

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

You still don't have a BrandName value, but do you really need one in this case? 您仍然没有BrandName值,但是在这种情况下您真的需要一个吗? It's duplicated data. 它是重复的数据。 The model can dynamically determine the BrandName from the known BrandID . 该模型可以动态地确定BrandName从已知BrandID So BrandName doesn't need to be a read/write property on the model, it can just be a read-only property which fetches the BrandName based on the model's BrandID . 因此, BrandName不必是模型上的读/写属性,而可以只是基于模型的BrandID提取BrandName的只读属性。 It might be something as simple as: 它可能很简单:

public string BrandName
{
    get
    {
        var brandName = GetBrandName(BrandID);
        return brandName;
    }
}

In this case you'd implement GetBrandName to fetch the value from the data store. 在这种情况下,您将实现GetBrandName从数据存储中获取值。 Or do the whole thing in-line if it's clear and concise enough, that's up to you. 或者,如果整个过程足够清晰明了,则可以直接进行整件事,这取决于您。 You could also cache the value in a class-level private variable so that it only needs to be fetched once. 您还可以将值缓存在类级别的私有变量中,以便只需要提取一次即可。 (Just make sure to clear out that variable or re-fetch it any time BrandID changes.) (只要确保清除此变量或在BrandID更改时重新获取该变量即可。)

You could keep both properties as they are, but then you'd be responsible for making sure they stay synchronized for the life of the object, which includes the time it spends in the UI. 可以按原样保留这两个属性,但是您有责任确保它们在对象的生命周期中保持同步,包括对象在UI中所花费的时间。 Any time you have the same piece of information recorded in two places, you have the responsibility of keeping it synchronized. 每当您在两个地方记录了相同的信息时,您都有责任保持信息同步。 Which is never fun. 这从来没有好玩。 In this case you'd need two elements in the view (the second one could be a hidden form field, or perhaps a drop down list styled to be hidden), and you'd have to write some JavaScript to update one any time the other one changes. 在这种情况下,您需要在视图中包含两个元素(第二个元素可能是一个隐藏的表单字段,或者可能是样式为隐藏的下拉列表),并且您必须编写一些JavaScript来随时更新其他一项更改。

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

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