4
votes

I have the following PagedListModel:

public class PagedClientViewModel
{
    public int? Page { get; set; }
    public PagedList.IPagedList<ClientViewModel> Clients { get; set; }               
}

public class ClientViewModel
{        
    public string ClientNumber { get; set; }
    public bool UseThisClient{ get; set; }
}

My view looks like this:

@using (Html.BeginForm("Index", "Home", FormMethod.Get, new { id = "Form" }))
{
    @foreach (var item in Model.Clients)
    {
       @Html.DisplayFor(modelItem => item.ClientNumber)
       @Html.CheckBoxFor(modelItem => item.UseThisClient)
    }    

 @Html.HiddenFor(model => model.Clients)            
}

Controller Action:

 public ActionResult Index(PagedClientViewModel model)
 {
  //...process all clients in the list
 }

I want to post the model back to the controller so that I can process which checkboxes have been ticked, but I get the following error: I kind of understand that the error is because I'm posting back an interface but I cant find a way around that. How can I get this work?

Cannot create an instance of an interface. at System.RuntimeTypeHandle.CreateInstance(RuntimeType type, Boolean publicOnly, Boolean noCheck, Boolean& canBeCached, RuntimeMethodHandleInternal& ctor, Boolean& bNeedSecurityCheck) at System.RuntimeType.CreateInstanceSlow(Boolean publicOnly, Boolean skipCheckThis, Boolean fillCache, StackCrawlMark& stackMark) at System.RuntimeType.CreateInstanceDefaultCtor(Boolean publicOnly, Boolean skipCheckThis, Boolean fillCache, StackCrawlMark& stackMark)
at System.Activator.CreateInstance(Type type, Boolean nonPublic)
at System.Activator.CreateInstance(Type type) at System.Web.Mvc.DefaultModelBinder.CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType) at System.Web.Mvc.DefaultModelBinder.BindSimpleModel(ControllerContext controllerContext, ModelBindingContext bindingContext, ValueProviderResult valueProviderResult) at System.Web.Mvc.DefaultModelBinder.BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) at System.Web.Mvc.DefaultModelBinder.GetPropertyValue(ControllerContext controllerContext, ModelBindingContext bindingContext, PropertyDescriptor propertyDescriptor, IModelBinder propertyBinder)
at System.Web.Mvc.DefaultModelBinder.BindProperty(ControllerContext controllerContext, ModelBindingContext bindingContext, PropertyDescriptor propertyDescriptor) at System.Web.Mvc.DefaultModelBinder.BindProperties(ControllerContext controllerContext, ModelBindingContext bindingContext) at System.Web.Mvc.DefaultModelBinder.BindComplexElementalModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Object model)
at System.Web.Mvc.DefaultModelBinder.BindComplexModel(ControllerContext controllerContext, ModelBindingContext bindingContext) at System.Web.Mvc.DefaultModelBinder.BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) at System.Web.Mvc.ControllerActionInvoker.GetParameterValue(ControllerContext controllerContext, ParameterDescriptor parameterDescriptor) at System.Web.Mvc.ControllerActionInvoker.GetParameterValues(ControllerContext controllerContext, ActionDescriptor actionDescriptor) at System.Web.Mvc.Async.AsyncControllerActionInvoker.<>c_DisplayClass25.b_1e(AsyncCallback asyncCallback, Object asyncState) at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResult1.Begin(AsyncCallback callback, Object state, Int32 timeout) at System.Web.Mvc.Async.AsyncControllerActionInvoker.BeginInvokeAction(ControllerContext controllerContext, String actionName, AsyncCallback callback, Object state) at System.Web.Mvc.Controller.<>c__DisplayClass1d.<BeginExecuteCore>b__17(AsyncCallback asyncCallback, Object asyncState) at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResult1.Begin(AsyncCallback callback, Object state, Int32 timeout) at System.Web.Mvc.Controller.BeginExecuteCore(AsyncCallback callback, Object state) at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResult1.Begin(AsyncCallback callback, Object state, Int32 timeout) at System.Web.Mvc.Controller.BeginExecute(RequestContext requestContext, AsyncCallback callback, Object state) at System.Web.Mvc.Controller.System.Web.Mvc.Async.IAsyncController.BeginExecute(RequestContext requestContext, AsyncCallback callback, Object state) at System.Web.Mvc.MvcHandler.<>c__DisplayClass8.<BeginProcessRequest>b__2(AsyncCallback asyncCallback, Object asyncState) at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResult1.Begin(AsyncCallback callback, Object state, Int32 timeout) at System.Web.Mvc.MvcHandler.BeginProcessRequest(HttpContextBase httpContext, AsyncCallback callback, Object state) at System.Web.Mvc.MvcHandler.BeginProcessRequest(HttpContext httpContext, AsyncCallback callback, Object state) at System.Web.Mvc.MvcHandler.System.Web.IHttpAsyncHandler.BeginProcessRequest(HttpContext context, AsyncCallback cb, Object extraData) at System.Web.HttpApplication.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)

1
There are ways around this problem which I have used in my project in past. But let me ask you this first - Do you have to post and interface type instead of a concrete class type?Suhas
I think I do have to post the interface type as when I populate the list of clients I need to call model.Clients = clients.ToPagedList(pageIndex, 25); which returns the interface type. I have tried to convert the IPagedList<ClientViewModel> to a PagedList<ClientViewModel> but havent succeeded.woggles
This worked for me in the end: stackoverflow.com/questions/14356152/…woggles

1 Answers

9
votes

Work around for this problem is to pass the paging meta data as separate property and reconstruct the IPagedList in the view. Like below

public class PagedClientViewModel
{
    public int? Page { get; set; }
    public List<ClientViewModel> Clients { get; set; }
    public IPagedList PagingMetaData { get; set; } 
}

gererating th metadata

pagedClientViewModel.PagingMetaData = new StaticPagedList<ClientViewModel>(pagedClientViewModel.Clients, pageIndex, pageSize, TotalClients).GetMetaData();

constructing the pager in the view

<div style="text-align: center">
    @Html.PagedListPager(new StaticPagedList<ClientViewModel>(Model.Clients, Model.PagingMetaData), page => Url.Action("<actionname>", new { page }), PagedListRenderOptions.Classic)
</div>