Search code examples
c#genericsumbracoumbraco7

In Umbraco, how can I bind a generic list of Objects to my View?


Something strange is happening in my umbraco project where I have a repository set up like so;

public class HireItemsRepo:BaseGenericRepository<YouHireItContext,HireItem>
{
   public List<HireItemViewModel> PopulateHireItemViewModel(RenderModel model)
    { List<HireItemViewModel> HireItems = new List<HireItemViewModel>();   
        foreach (var Hireitem in base.GetAll())
        {
            HireItems.Add(
              new HireItemViewModel(model.Content)
              {
                  Title = Hireitem.Title,
                  Price = Hireitem.Price
              }
           );
        }
        return HireItems;
    }

}

which I'm using in my controller like this

 public class HiresController : RenderMvcController
    {
        // GET: Hire
        public override ActionResult Index(RenderModel model)
        {

            HireItemsRepo repo = new HireItemsRepo();
            var VM = repo.PopulateHireItemViewModel(model);

                return View("Hires",VM.ToList());
        }
    }

And using that model in the view like this;

    @model List<You_Hire_It.Models.HireItemViewModel>

   /*HTML starts here*/

It's strange because if I try to use that model as a List, Umbraco will blow up with the following error;

Cannot bind source type System.Collections.Generic.List`1[[You_Hire_It.Models.HireItemViewModel, You_Hire_It, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]] to model type Umbraco.Web.Models.RenderModel.

However, if I refactor all the code to use the model on it's own as if I only have one set of values to use, it has no problem with it!

Could anybody point me in the right direction with this please?

Many thanks in advance!


Solution

  • You can inherit from RenderModel as DZL suggests. However, I generally prefer to use route hijacking which would enable me to keep my models simple.

    Instead of the Index method in your RenderMvcController, you can create a method with the same name as your view. I note your view is called Hires. So change your controller code to this:

    public class HiresController : RenderMvcController
    {
        // GET: Hire
        public ActionResult Hires(RenderModel model)
        {
            HireItemsRepo repo = new HireItemsRepo();
            var VM = repo.PopulateHireItemViewModel(model);
    
            return CurrentTemplate(VM)
        }
    }
    

    You now need to have your view inherit from UmbracoViewPage. So at the top of your view replace the @model line with the following:

    @inherits UmbracoViewPage<List<HireItemViewModel>>
    

    Your model in the view is now of type List<HireItemViewModel> which I think is what you want.

    So to iterate the items you would use:

    @foreach(var item in Model){
    {
        // etc
    }
    

    Additionally, as this view now inherits from UmbracoViewPage, you have access to the UmbracoContext - just use @Umbraco

    For example:

    @Umbraco.TypedContentAtRoot().Where(x=>x.DocumentTypeAlias == "HomePage")
    

    or

    @Umbraco.AssignedContentItem etc