视图模型和验证中包含的选择列表的视图

时间:2012-12-26 11:11:39

标签: asp.net-mvc-3 validation

我的情景: 我的模型是“项目”,其中包含0或多个税(模型“税”)

“项目” - >有0或n - > “税”

我有一个名为“VMItem”的MVC视图模型,它有一个“Item”对象,所有税(“TaxDic”)和选定的税(“Taxes”)。 MVC页面绑定到此视图模型(“ViewItem”)。

要求: 我希望MVC显示所有税款的列表框,并允许用户在创建项目时为每个项目选择相关税。

以下是我的代码,

参考以下代码,ListBox for Taxes不是必填字段。但是当我在ListBox上提交了一些选择的表单时,它会在ListBox周围显示红色框,如果我在ListBox上没有选择任何内容并提交,则看起来没有错误。

请看下面的场景..如果有更好的方法来实现这一点,请有人指导我。

模型

public class Item 
{
    [Display(Name="Item ID")]
        public virtual Guid ItemID { get; set; }

        [Required]
        [Display(Name = "Name")]
        public virtual string Name { get; set; }

        [Required]
        [Display(Name="Price")]
        public virtual decimal Price { get; set; }

        public virtual IEnumerable<Tax> Taxes { get; set; }

}

查看模型

public class VMItem
{
    public Item Item { get; set; }
        public IEnumerable<Tax> Taxes { get; set; }
        public IEnumerable<SelectListItem> TaxDic { get; set; }
}

生成控制器类中的选择列表项的功能

private VMItem GenerateViewModel(Item Item)
{
        IEnumerable<Tax> Taxes = TaxServices.FindAll();
        IList<SelectListItem> taxDic = new List<SelectListItem>();

        // Generating Taxes and taxDic here..

        VMItem VmItem = new VMItem
        {
            Item = Item,
            Taxes = Taxes,
            TaxDic = taxDic
        };

        return VmItem;
    }

Contorller行动

// GET: /Product/Add

public ActionResult Add()
{
    return View(GenerateViewModel(new Item()));
}

[HttpPost]
public ActionResult Add(VMItem collection)
{
    Item item = new Item();
        try
        {
         if(ModelState.IsValid)
         {
        item = collection.Item;        

        var taxes = collection.Taxes;
            return View(GenerateViewModel(collection.Item));                
             }
         // else..

    }
        // catch...
}

浏览

<% using (Html.BeginForm()) { %>

<!-- more codes for other fields -->

<%: Html.ListBoxFor(model => model.Taxes, Model.TaxDic) %>

<!-- submit button goes below -->

<% } %>

2 个答案:

答案 0 :(得分:1)

这看起来像是多对多的关系,所以首先检查您的税级是否如下所示:

public class Tax
{
  public Guid TaxId { get; set;}
  public virtual ICollection<Item> Items { get; set;}
}

然后在上下文类中的OnModelCreating函数内添加:

modelBuilder.Entity<Item>()
     .HasMany(i => i.Taxes).WithMany(t => t.Items)
     .Map(t => t.MapLeftKey("ItemId")
         .MapRightKey("TaxId")
         .ToTable("ItemsTaxes"));

视图模型

public class ItemTaxViewModel
{
   public Item item { get; set; }
   public virtual ICollection<AssignedTaxes> Taxes { get; set; }
}

public class AssignedTaxes
{
  public int TaxId { get; set; }
  public bool Assigned { get; set; }
}

控制器操作

public ActionResult Create()
{
   var newItemVM = new ItemTaxViewModel
          {
              Item = new Item(),
              Taxes = PopulateTaxes()
          };
    return View(newItemVM);
 }

[HttpPost]
public ActionResult Create(ItemTaxViewModel itemTaxViewModel)
{
   if(ModelState.IsValid)
   {
      var item = new Item();
      item = itemTaxViewModel.Item;
      AddOrUpdateTaxes(item, itemTaxViewModel.Taxes);
      context.Items.Add(item);
      context.SaveChanges();
      return RedirectToAction("Index");
   }
   return View(itemTaxViewModel);
}

帮助方法

private List<AssignedTaxes> PopulateTaxes()
{
  var taxes = context.Taxes;
  var assignedTaxes = new List<AssignedTaxes>();
  foreach(var tax in taxes)
  {
    assignedTaxes.Add(new AssignedTaxes
      {
        TaxId = tax.TaxId,
        Assigned = false
      });
  }
  return assignedTaxes;
 }

 private void AddOrUpdateTaxes(Item item, ICollection<AssignedTaxes> assignedTaxes)
 {
   foreach(var assignedTax in assignedTaxes)
   {
      if(assignedTax.Assigned)
      {
         item.Taxes.Add(context.Taxes.Single(t => t.TaxId == assignedTax.TaxId));
      }
   }
  }
/ Views / Shared / EditorTemplates

下的EditorTemplate
@model AssignedTaxes
@using projectName.ViewModels

 <fieldset>
     @Html.HiddenFor(model => model.TaxId)
     @Html.CheckBoxFor(model => model.Assigned)
 </fieldset>

查看

<div class="editor-field">
   @Html.EditorFor(model => model.Taxes)
<div class="editor-field">

似乎喜欢很多工作,但它是实现多对多复选框的最干净方法之一,我在完成了许多教程之后想出了这些复选框。

答案 1 :(得分:0)

@Luis,你的方式看起来不错但是太复杂了,最后你用复选框结束了它。可能是更好的方式。我提出了一个解决方案,这对我来说很简单。我在下面发布。请给我一个反馈意见,我是否应继续使用或需要改进。

控制器

        IEnumerable<Tax> Taxes = _TaxServices.FindTax();
        IList<SelectListItem> taxDic = new List<SelectListItem>();
        foreach (Tax tax in Taxes)
        {
            SelectListItem item = new SelectListItem();
            item.Value = tax.TaxID.ToString();
            item.Text = tax.Name;
            taxDic.Add(item);
        }

        VMItem VmItem = new VMItem
        {
            Item = Item,
            TaxDic = taxDic,
        };

        // Adding selected taxes to the list
        IList<int> SelectedTaxes = new List<int>();
        if (Item.Taxes != null && Item.Taxes.Count > 0)
        {
            foreach (Tax tax in Item.Taxes)
            {
                SelectedTaxes.Add(tax.TaxID);
            }
        }
        VmItem.SelectedTax = SelectedTaxes;

        return view(VmItem);

查看

<%: Html.ListBoxFor(model => model.SelectedTax, Model.TaxDic) %>

控制器[HttpPost]

    item.Taxes = new Iesi.Collections.Generic.HashedSet<Tax>();
    if (vmItem.SelectedTax.Count() > 0)
    {
        IEnumerable<int> SelectedTaxesIDs = vmItem.SelectedTax.ToList();
        foreach (int n in SelectedTaxesIDs)
        {
            item.Taxes.Add(_TaxServices.FindTax(n));
        }
    }

请以这种方式提供反馈。 感谢。