2013-10-14 3 views
2

У меня есть объект модели представления, который содержит List другого типа объекта модели. Когда пользователь делает запрос на странице, если возвращенный List содержит более 300 записей, мы хотим использовать пейджинг, чтобы сократить время загрузки (некоторые результаты поиска могут возвращать более 14 тыс. Записей). Плагин подкачки, который мы используем can be found here.Невозможно создать экземпляр интерфейса (PagedList)

После того, как результаты были отображены на странице, у пользователя есть возможность установить флажок рядом с конкретными результатами, ввести некоторую информацию в текстовое поле ввода, нажать submit, и иметь выбранные записи, отредактированные с информацией из текстового поля.

Поскольку нам нужно использовать IPagedList<> для того, чтобы дать возможность подкачки, однако, если вы попали представить (и до того, как страница даже попадает на контроллер), мы получаем следующую ошибку:

    Cannot create an instance of an interface. 

View Model

Это два объекта списка, которые мы используем для подкачки. Объект 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); 

Посмотреть

Это форма, которая отображает результаты поиска. Если пользователь проверяет флажок, то нажимает либо кнопки clone, либо delete, результаты должны быть отправлены обратно в метод контроллера 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> 
    } 
} 

EDIT

Per комментарий ниже, вот сигнатура метода форма проводки к. Он содержит экземпляр ZipCodeIndex, которая загружается на странице изначально, плюс текст из button определить ли мы делаем clone или delete

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

Второй Редактировать

Попробовал метод от this question, но все еще получает исходное сообщение об ошибке («невозможно создать экземпляр интерфейса»).

+0

Если ошибка происходит до контроллера, но после того, как submit, то нам, вероятно, понадобится код перед контроллером. Возможно, подписи контроллера и просмотра. –

+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

Был ли это 'public IPagedList PagingMetaData {get; задавать; } '? –

+0

@ SH-В окольном пути я так думаю. – NealR

Смежные вопросы