2013-10-14 82 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