How do I create a view model for a populated drop

2019-01-11 17:50发布

问题:

I'm trying to teach myself MVC3. Im converting from webforms.

I need to create a view model that includes a dropdown list that I can pass to the controller and eventually render in the View.

How can I accomplish this? I have the skeleton but I dont know what the code is to actually create the name value pairs for the view.

namespace DH.ViewModels
{
    public class SharedLayoutViewModel
    {
        public IEnumerable<SelectListItem> Products
        {
            //some code to setup the value/name pairs to be rendered in the view.
            //example: 
            //<option value="1">Mustard</option>
            //<option value="2">Ketchup</option>
            //<option value="3">Mayo</option>
            //<option value="4">Relish</option>
            //<option value="5">BBQ</option>
         }
     }
  }

Thanks

回答1:

I would create a class for Product and the create Products Property in my main viewmodel which is of type List

public class ProductViewModel
{
  public int ID { set;get;}
  public string Name { set;get;}
}

public class OrderViewModel
{
  public int OrderNumber { set;get;}
  public List<ProductViewModel> Products { set;get;}
  public int SelectedProductId { set;get;}    
}

and in your Controller Action method

public ActionResult Order()
{     
   var orderVM=new OrderViewModel();
   //Items hard coded for demo. You may replace with values from your db
   orderVM.Products= new List<ProductViewModel>
    {
        new ProductViewModel{ ID=1, Name="IPhone" },
        new ProductViewModel{ ID=2, Name="MacBook Pro" },
        new ProductViewModel{ ID=3, Name="iPod" }           
    };
   return View(orderVM);
}

and in your view which is strongly typed to OrderViewModel.

@model ORderViewModel
@using (Html.BeginForm())
{
  <p> 
    @Html.DropDownListFor(x => x.SelectedProductId ,
                     new SelectList(Model.Products, "ID", "Name"), "-- Select Product--")
  </p>
  <input type="submit" />
}

I have added a SelectedProductId property also, so you will get the user selected value from the dropdown in that Property when user post the form back to the controller.

You can also use the generic SelectListItem type collection as your view model property to transfer the dropdown data instead of your custom ProductViewModel collection.

public class OrderViewModel
{
  public int OrderNumber { set;get;}
  public List<SelectListItem> Products { set;get;}
  public int SelectedProductId { set;get;}    
}

and in the GET action,

public ActionResult Order()
{     
   var orderVM=new OrderViewModel();
   //Items hard coded for demo. You may replace with values from your db
   orderVM.Products= new List<SelectListItem>
    {
        new SelectListItem {Value = "1", Text = "IPhone"},
        new SelectListItem {Value = "2", Text = "MacBook"},
        new SelectListItem {Value = "3", Text = "Candy"}
    };
   return View(orderVM);
}

And in your view,

@Html.DropDownListFor(x => x.SelectedProductId, Model.Products, "-- Select Product--")

EDIT : As per the request from OP, edited the answer to have the Property returning static items as products

I added a get implementation to Products property to return a list of static products.

public class OrderViewModel
{
        private List<ProductViewModel> _products;
        public int OrderNumber { set; get; }
        public List<ProductViewModel> Products
        {
            get
            {
                if (_products == null)
                {
                    _products = new List<ProductViewModel>();
                    _products.Add(new ProductViewModel { ID = 1, Name = "Ketchup" });
                    _products.Add(new ProductViewModel { ID = 1, Name = "Mustard" });
                    _products.Add(new ProductViewModel { ID = 1, Name = "Relish" });
                    _products.Add(new ProductViewModel { ID = 1, Name = "Mayo" });
                }
                return _products;
            }
        }
       public int SelectedProductId { set;get;}
}

Now in your controller, you don't need to call the GetAvailableProductsmethod as it is already there. So the controller will looks like this.

    public ActionResult Order()
    {
        OrderViewModel orderVM = new OrderViewModel();           
        return View(orderVM);
    }

Here is the output.

If you have many items in the products, move it to a method and call that method int he get implementation instead of writing that there. That is much cleaner approach.



回答2:

I prefer to do it this way.

@Html.DropDownListFor(m => m.ProductId, new SelectList(Model.Products, "ID", "Name"))

So my view model just contains a list of products and generate the select list on the view.



回答3:

Why can't you just use SelectList within your ViewModel? It's kind of abstraction that contains selected value and list of items itself. You can implement Display / Editor templates and define attribute DataTypeAttribute/UIHintAttribute associate specific template with Select List.

public class ProductViewModel
{
    public int ID { set;get;}
    public string Name { set;get;}
    public SelectList Items {get;set;}
}