2

我有一个包含List另一个模型对象类型的视图模型对象。当用户在页面上进行查询时,如果List返回包含超过 300 条记录,我们希望使用分页来降低加载时​​间(某些搜索结果可以返回超过 14k 条记录)。我们使用的分页插件可以在这里找到。

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

由于我们需要使用 anIPagedList<>来启用分页,但是,当您点击提交时(甚至在页面点击控制器之前),我们会收到以下错误:

                 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我发现我必须将相同的搜索条件从页面传回 index 方法,因此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以确定我们是否正在clone执行delete

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

第二次编辑

尝试了这个问题的方法,但仍然收到原始错误消息(“无法创建接口的实例”)。

4

2 回答 2

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>
     .
     .
于 2013-10-14T21:32:37.807 回答
0

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

ASP.Net MVC 自定义模型绑定解释

基本上,您的活页夹将为您解析您的模型,确定要实现哪种类型的 IPagedList<>。

于 2013-10-14T19:23:25.283 回答