2013-10-14 60 views
2

我有一个视图模型对象,其中包含另一个模型对象类型List。当用户在页面上进行查询时,如果返回的List包含超过300条记录,我们希望使用分页来减少加载时间(某些搜索结果可能会返回超过14k条记录)。我们正在使用的分页插件can be found here.无法创建接口的实例(PagedList)

一旦结果显示在页面上,用户就可以点击特定结果旁边的复选框,在输入文本框中键入一些信息,点击提交,并使用文本框中的信息编辑选定的记录。

因为我们需要的,以便使分页使用一个IPagedList<>,然而,当你点击提交(和之前的页面,甚至打控制器),我们得到以下错误:

    Cannot create an instance of an interface. 

视图模型

这些是我们用于分页的两个列表对象。 zipCodeTerritory对象保存查询的结果。 pagedTerritoryList用于仅显示用户所在的特定页面上的结果。

//Paging List objects 
    public IPagedList<ZipCodeTerritory> pagedTerritoryList { get; set; } 
    public List<ZipCodeTerritory> zipCodeTerritory { get; set; } 
    public IPagedList PagingMetaData { get; set; } 

控制器

这是我们的基本搜索。 .ToPagedList方法用于指定我们要显示的结果范围,并将它们放在pagedTerritoryList对象中。

   //set Paged List counter variables 
       int pageNumber = page ?? 1; 
       int pageSize = 300; 

       //Determine if Territory present? 
       if (string.IsNullOrWhiteSpace(search.searchTerritory)) 
       { 
        //State Code ONLY search 
        search.zipCodeTerritory = (from z in db.ZipCodeTerritory 
               where z.StateCode.Equals(search.searchState) 
               select z).ToList(); 
       } 
       else if(string.IsNullOrWhiteSpace(search.searchState)) 
       { 
        //Territory ONLY search 
        search.zipCodeTerritory = (from z in db.ZipCodeTerritory 
               where z.IndDistrnId.Equals(search.searchTerritory) 
               select z).ToList(); 
       } 
       else 
       { 
        //Territory AND state search 
        search.zipCodeTerritory = (from z in db.ZipCodeTerritory 
               where z.IndDistrnId.Equals(search.searchTerritory) && 
                z.StateCode.Equals(search.searchState) 
               select z).ToList(); 
       } 

       //Convert list to IPagedList for pagining on Index 
       search.pagedTerritoryList = search.zipCodeTerritory.ToPagedList(pageNumber, pageSize); 

       //Set Paged List objects 
       search.PagingMetaData = new StaticPagedList<ZipCodeTerritory>(search.zipCodeTerritory, pageNumber, pageSize, 
                     search.zipCodeTerritory.Count).GetMetaData(); 

       return View(search); 

查看

这是一个显示搜索结果的形式。如果用户选中该复选框,然后点击clonedelete按钮,则结果应该被回送到控制器的Update方法并执行适当的编辑或删除。用户想要在编辑中叠加的信息以格式输入到newTerritory/Description/etc字段中(在table之上)。

关于@Html.PagedListPager我发现我不得不从页面传回给索引方法相同的搜索条件,因此RouteValueDictionary中的参数数量过大。

@if (Model.zipCodeTerritory.Count > 0) 
{ 
    using (Html.BeginForm("Update", "ZipCodeTerritory", FormMethod.Post)) 
    { 
     @Html.HiddenFor(model => model.searchZip) 
     @Html.HiddenFor(model => model.searchDate) 
     @Html.HiddenFor(model => model.searchState) 

     <div id="cloneBox"> 
      <div id="rw1"> 
       @Html.LabelFor(model => model.newTerritory) 
       @Html.TextBoxFor(model => model.newTerritory, new { style = "width: 30px;padding-left:10px;", maxLength = 3 }) 
       @Html.LabelFor(model => model.newDescription) 
       @Html.TextBoxFor(model => model.newDescription, new { style = "width: 250px;padding-left:10px;", maxLength = 30 }) 
       @Html.LabelFor(model => model.newEffectiveDate)  
       @Html.TextBoxFor(model => model.newEffectiveDate, new { style = "width: 80px;padding-left:10px;" }) 
       <div id="rw2" style="padding-top: 10px;"> 
        @Html.LabelFor(model => model.newChannelCode) 
        @Html.DropDownListFor(model => model.newChannelCode, Model.ChannelCodes, " ") 
        @Html.LabelFor(model => model.newStateCode) 
        @Html.DropDownListFor(model => model.newStateCode, Model.StateCodes, " ") 
       </div>         
      </div> 
     </div> 
     <br/> 
     <div id="buttonDiv"> 
      <button type="submit" id="CloneButton" name="button" value="clone">Apply New Data</button> 
      <button type="submit" id="deleteButton" name="button" value="delete">Delete Selected Items</button>    
     </div> 


     @*Display paging only if necessary*@ 
     if (Model.pagedTerritoryList.Count >= 300) 
     { 
      <div id="pagingDiv"> 
       @Html.PagedListPager(new StaticPagedList<Monet.Models.ZipCodeTerritory>(Model.zipCodeTerritory, Model.PagingMetaData) , 
      Page => Url.Action("Index", new RouteValueDictionary() 
       { 
        { "Page", Page}, 
        { "searchZip", Model.searchZip }, 
        { "searchActiveOnly", Model.searchActiveOnly }, 
        { "searchDate", Model.searchDate }, 
        { "searchState", Model.searchState }, 
        { "searchTerritory", Model.searchTerritory }, 
        { "searchChannel" , Model.searchChannelCode } 
       }), PagedListRenderOptions.DefaultPlusFirstAndLast) 
      </div>    
     } 

     <table id="thetable" class="tablesorter" > 
      <thead> 
       <th>@Html.CheckBox("SelectAll")</th> 
       <th>State</th> 
       <th>Territory</th> 
       <th>Zip</th> 
       <th>Description</th> 
       <th>Effective</th> 
       <th>End Date</th> 
       <th>Last Update Date</th> 
       <th>Channel</th> 
       <th></th> 
      </thead> 
      <tbody id="tableBody"> 
       @for (int i = 0; i < Model.pagedTerritoryList.Count; i++) 
       { 
        <tr id="@(Model.lastEditedId == Model.pagedTerritoryList[i].Id ? "lastEdit" : "")"> 
         <td> 
          @Html.CheckBoxFor(model => model.pagedTerritoryList[i].Update) 
          @Html.HiddenFor(model => model.pagedTerritoryList[i].Update) 
         </td> 
         <td> 
          @Html.DisplayFor(model => model.pagedTerritoryList[i].StateCode) 
          @Html.HiddenFor(model => model.pagedTerritoryList[i].StateCode) 
         </td> 
         <td> 
          @Html.DisplayFor(model => model.pagedTerritoryList[i].IndDistrnId) 
          @Html.HiddenFor(model => model.pagedTerritoryList[i].IndDistrnId) 
         </td> 
         <td> 
          @Html.DisplayFor(model => model.pagedTerritoryList[i].ZipCode) 
          @Html.HiddenFor(model => model.zipCodeTerritory[i].ZipCode) 
         </td> 
         <td> 
          @Html.DisplayFor(model => model.pagedTerritoryList[i].DrmTerrDesc) 
          @Html.HiddenFor(model => model.pagedTerritoryList[i].DrmTerrDesc) 
         </td> 
         <td> 
          @Html.DisplayFor(model => model.pagedTerritoryList[i].EffectiveDate) 
          @Html.HiddenFor(model => model.pagedTerritoryList[i].EffectiveDate) 
         </td> 
         <td> 
          @if (Model.pagedTerritoryList[i].EndDate.Date != DateTime.MaxValue.Date) 
          { 
           @Html.DisplayFor(model => model.pagedTerritoryList[i].EndDate) 
           @Html.HiddenFor(model => model.pagedTerritoryList[i].EndDate)         
          } 
         </td> 
         <td> 
          @Html.DisplayFor(model => model.pagedTerritoryList[i].LastUpdateDate) 
          @Html.HiddenFor(model => model.pagedTerritoryList[i].LastUpdateDate) 
         </td> 
         <td> 
          @Html.DisplayFor(model => model.pagedTerritoryList[i].ChannelCode) 
          @Html.HiddenFor(model => model.pagedTerritoryList[i].ChannelCode) 
         </td> 

         @if (ViewBag.SecurityLevel >= 4) 
         { 
          <td> 
           @Html.ActionLink("Edit", "Edit", new 
            { 
             id = Model.zipCodeTerritory[i].Id, 
             searchZip = Model.searchZip, 
             searchActiveOnly = Model.searchActiveOnly, 
             searchDate = Model.searchDate, 
             searchState = Model.searchState, 
             searchTerritory = Model.searchTerritory, 
             searchChannelCode = Model.searchChannelCode 
            }) 
           @Html.HiddenFor(model => model.zipCodeTerritory[i].Id) 
          </td>        
         } 

        </tr> 
       } 
      </tbody> 
     </table> 
    } 
} 

编辑

每下面的评论,这里是形式发布给该方法的签名。它包含了获取网页上加载本来是ZipCodeIndex的实例,加上从button文本,以确定我们是否在做一个clonedelete

[HttpPost] 
    public ActionResult Update(ZipCodeIndex updateZip, string button) 
    { 

第二个编辑

试过方法从this question,但仍然收到原始错误消息(“无法创建一个接口的实例”)。

+0

如果错误的控制器之前,但之后会发生提交,那么我们可能需要在控制器之前的代码。可能是控制器和视图的签名。 –

+0

好点,刚刚发布在上面的修改中。谢谢! – NealR

+0

你没有将页面传递给签名。 – DarthVader

回答

5

我能完全破解我的出路,但我不认为这是最好的解决方案。如果有人能够提供更好的答案,我会喜欢它,但我会在此同时发布。

由于IPagedList对象的构建是为了保存List<>的特定范围,我只是在我的视图模型上创建了一个显示属性,并在我的视图中使用了它。此列表(而不是IPagedList)被发回控制器进行更新,因此不会出现界面怪异现象。

视图模型

//Paging List objects 
    public IPagedList<ZipCodeTerritory> pagedTerritoryList { get; set; } 
    public List<ZipCodeTerritory> zipCodeTerritory { get; set; } 
    public List<ZipCodeTerritory> displayForPaging { get; set; } 

控制器

//Convert list to IPagedList for pagining on Index 
    search.pagedTerritoryList = search.zipCodeTerritory.ToPagedList(pageNumber, pageSize); 
    search.displayForPaging = search.pagedTerritoryList.ToList(); 

查看

<td> 
     @Html.CheckBoxFor(model => model.displayForPaging[i].Update) 
     @Html.HiddenFor(model => model.displayForPaging[i].Update) 
    </td> 
    <td> 
    . 
    . 
+0

谢谢 - 正是我所需要的 – user1750537

+0

您节省了我的时间! –

0

我发现具有接口属性的模型需要创建一个ModelBinder来确定要使用哪个实现。

ASP.Net MVC Custom Model Binding explanation

基本上,你的粘结剂将分析模型对你来说,确定实施哪种类型IPagedList <>的。

+0

是否是公共IPagedList PagingMetaData {get;组; }'? –

+0

@ SH-以一种迂回的方式,我认为是这样。 – NealR