如何正确使用ViewModels

时间:2014-09-16 09:06:33

标签: asp.net-mvc model-binding asp.net-mvc-viewmodel

我创建了一个简单的应用程序,其中有一个产品列表和搜索过滤器边栏。(http://i.imgur.com/4tAHgiK.png) 我遇到了分页问题(使用PagedList),因为在过滤结果并继续下一页(http://i.imgur.com/xh3SSN7.png)后,我得到一个空页面。原因很清楚。我在控制器操作参数中获取数据,因此在单击下一页按钮后,过滤器数据丢失。所以我决定将这些数据存储在某个地方。

我被告知我需要ViewModel,所以我创建了另一个带有侧栏字段的模型FilterModel

public class FilterModel {
    public string Manufacturer { get; set; }
    public string Name { get; set; }
    public int? MinPrice { get; set; }
    public int? MaxPrice { get; set; }
}

这是Products型号

public partial class Products {
    [Key]
    public int ProductID { get; set; }
    public string Manufacturer { get; set; }
    public string Name { get; set; }
    ......
    public int Price { get; set; }
}

并将它们放入ViewModel

public class HomeViewModel {
    public IPagedList<Products> Repository { get; set; }
    public FilterModel FilterView { get; set; }
}

这些是我的控制器 - HomeController显示了应显示过滤产品的每件商品和SearchFilterController

public class HomeController : Controller {
    IProductRepository _repository;
    public HomeController(IProductRepository rep) {
        _repository = rep;
    }

    public ActionResult Index(int page=1) {
        ViewBag.Manufacturers = Manufacturers.ManufacturersList(_repository);
        var model =
            (from p in _repository.Product
             orderby p.Price descending
             select p).ToPagedList(page, 2);
        ViewBag.Title = "Home";
        return View(model);
    }
}

public class SearchFilterController : Controller {
        IProductRepository _repository;
        public SearchFilterController(IProductRepository rep) {
            _repository = rep;
        }

        [HttpPost]
        public ActionResult Filter(FilterModel filterModel, int page = 1) {
            ViewBag.Manufacturers = Manufacturers.ManufacturersList(_repository);
            var model =
                (from p in _repository.Product
                 where (p.Manufacturer == filterModel.Manufacturer || p.Name.Contains(filterModel.Name) || 
                    p.Price >= filterModel.MinPrice || p.Price <= filterModel.MaxPrice)
                 orderby p.Price descending
                 select p).ToPagedList(page, 1);
            ViewBag.Title = "Results";
            return View(model);
        }
    }

在两个控制器中,我都会通过views PagedList<Products>模型,但我猜他们应该HomeViewModel

以下是我的看法: IndexHomeController

@model SmartPhoneCatalog.Models.HomeViewModel
@using System.Linq
@using PagedList
@using PagedList.Mvc
@using SmartPhoneCatalog.Domain.Abstract

...

<div id="root">
     @Html.Partial("_Sidebar", Model)

     @Html.Partial("_ProductsList", Model)
</div>

<br>
<div class="pagedList" data-sc-target="#products">
    @Html.PagedListPager(Model.Repository, page => Url.Action("Index", "Home", new { page }),
                PagedListRenderOptions.ClassicPlusFirstAndLast);
</div>

FilterSearchFilterController

@model SmartPhoneCatalog.Models.HomeViewModel
@using System.Linq
@using PagedList
@using PagedList.Mvc
@using SmartPhoneCatalog.Domain.Abstract

...

<div id="root">
    @Html.Partial("_Sidebar", Model)

    @Html.Partial("_ProductsList", Model)
</div>

<br>
<div class="pagedList" data-sc-target="#products">
    @Html.PagedListPager(Model.FilterModel, page => Url.Action("Filter", "SearchFilter", new { page }),
                PagedListRenderOptions.ClassicPlusFirstAndLast);
</div>

部分视图: _Sidebar

@model SmartPhoneCatalog.Models.HomeViewModel
@using System.Linq
@using PagedList
@using PagedList.Mvc

    <div id="filter" class="left">
        @using (Html.BeginForm("Filter", "SearchFilter")) {
            <div>
                <b>Manufacturer:</b> <br>
                <select name="manufacturer" class="form-control">
                    <option>@null</option>
                    @foreach (var item in ViewBag.Manufacturers) {
                        <option>@item</option>
                    }
                </select><br>

                <b>Name:</b> <br>@Html.EditorFor(model=>model.FilterModel.Name)<br>
                <b>Price From:</b> <br>@Html.EditorFor(model => model.FilterModel.Name)<br>
                <b>To:</b> <br>@Html.EditorFor(model => model.FilterModel.Name)<br>
                <button type="submit" value="search"><b>Search</b></button>
            </div>
        }
    </div>

我认为我在视图中做的一切都是正确的。但是我不知道如何传递它们模型的正确性和对象绑定是否正确。

有什么建议吗?

编辑:好的,我在控制器中创建了这个:创建了HomeViewModel对象并更改了此

var model =
            (from p in _repository.Product
             orderby p.Price descending
             select p).ToPagedList(page, 2);
return View(model);

进入这个:

_homeView.Repository =
            (from p in _repository.Product
             orderby p.Price descending
             select p).ToPagedList(page, 2);
return View(_homeView);

现在一切都有效,除了过滤结果后的分页(这就是为什么我做了所有这些:D)。所以我必须修复模型绑定

1 个答案:

答案 0 :(得分:4)

嗨我执行了你的代码..下面是更改

  

宣布像这样的模型

public class FilterModel
{
    public string Manufacturer { get; set; }
    public string Name { get; set; }
    public int? MinPrice { get; set; }
    public int? MaxPrice { get; set; }
}

public partial class Products
{
    public int ProductID { get; set; }
    public string Manufacturer { get; set; }
    public string Name { get; set; }
    public int Price { get; set; }
}

public class HomeViewModel
{
    public IPagedList<Products> Repository { get; set; }
    public FilterModel FilterView { get; set; }
}
  

控制器动作方法

 public class PagingController : Controller
{
    int pagesize = 2;

    public ActionResult Index(int page = 1)
    {
        HomeViewModel _HomeViewModel = new HomeViewModel();

        //call service and get products list
        AgentServiceReference.AgentServiceClient ServiceClient = new AgentServiceClient();
        var productlist = ServiceClient.GetProducts().ToPagedList(page, pagesize);

        //set IPagedList<Products> to our HomeViewModel Repository property
        _HomeViewModel.Repository = productlist;

        // set view bag  this we use for Drop Down list
        SetViewBags();
        ViewBag.Title = "Home";
        return View(_HomeViewModel);
    }


    [HttpGet]
    public ActionResult Filter(int page = 1)
    {
        //call service and get products list
        AgentServiceReference.AgentServiceClient ServiceClient = new AgentServiceClient();
        var productlist = ServiceClient.GetProducts().ToPagedList(page, pagesize);

        //set IPagedList<Products> to our HomeViewModel Repository property
        HomeViewModel _homeViewModel = new HomeViewModel();
        _homeViewModel.Repository = productlist;
        SetViewBags();
        return View("Index", _homeViewModel);
    }

    [HttpPost]
    public ActionResult Search(HomeViewModel HomeViewModel)
    {
        HomeViewModel _homeviewModel = new HomeViewModel();
        AgentServiceReference.AgentServiceClient ServiceClient = new AgentServiceClient();

        var productlist = ServiceClient.GetProducts();
        // do filter stuff here........
        var resultpagedList = productlist.ToPagedList(3, pagesize);

        _homeviewModel.Repository = resultpagedList;

        SetViewBags();
        return View("Index", _homeviewModel);
    }

    private void SetViewBags()
    {
        List<SelectListItem> manufactures = new List<SelectListItem>();
        for (int i = 0; i < 10; i++)
        {
            manufactures.Add(new SelectListItem { Text = "Text" + i, Value = "Value" + i, Selected = false });

        }
        ViewBag.Manufacturers = manufactures;
    }
}
  

Index.cshtml页面

@using System.Linq
@using PagedList
@using PagedList.Mvc
@model EntityLayer.HomeViewModel
@{
ViewBag.Title = "Index";
Layout = "~/Views/Shared/_Layout.cshtml";
}
@using (Html.BeginForm("Search", "Paging", FormMethod.Post))
{
<div id="root">
    @Html.Partial("_Sidebar", Model)
    @Html.Partial("_ProductsList", Model)
</div>
}
  

_Sidebar.cshtml

@model EntityLayer.HomeViewModel
@using System.Linq
@using PagedList
@using PagedList.Mvc
<div id="filter" class="left">
<div>
    <b>Manufacturer:</b>
    <br>        
    @Html.DropDownListFor(model => model.FilterView.Manufacturer, ViewBag.Manufacturers as IEnumerable<SelectListItem>)
    <b>Name:</b>
    <br>@Html.TextBoxFor(model => model.FilterView.Name)<br>
    <b>Price From:</b>
    <br>@Html.TextBoxFor(model => model.FilterView.MaxPrice)<br>
    <b>To:</b>
    <br>@Html.TextBoxFor(model => model.FilterView.MinPrice)<br>
    <button type="submit" value="search"><b>Search</b></button>
</div>

  

最后_ProductsList.cshtml

@model EntityLayer.HomeViewModel
@using System.Linq
@using PagedList
@using PagedList.Mvc
<table>
<tr>
    <th>Name</th>
    <th>Price</th>
</tr>

@foreach (var item in Model.Repository)
{
    <tr>
        <td>@item.Name</td>
        <td>@item.Price</td>
    </tr>
}

<div class="pagedList" data-sc-target="#products">
@Html.PagedListPager(Model.Repository, page => Url.Action("Filter", "Paging", new { page }),
            PagedListRenderOptions.ClassicPlusFirstAndLast);

  • 相应地更改EntityLayer.HomeViewModel的名称空间
  • 您遵循的方法可能不正确,因为每次部分视图确实需要特定模型时我们都会传递整个HomeViewModel。
  • 如果你使用ajax请求进行相同的操作会更好 请注意,由于您提供了图像,因此我没有应用布局。 结果图像是 On Load First Paging Given Model Values Model Binding When Post

希望它可以帮到你