Adding Paging to the Simple Photo Gallery

Turn the pageOver my last handful of posts, Building a Simple Photo Gallery in ASP.NET MVC Framework, Returning Thumbnails With the MVC Framework and Adding Lighbox.js to the Simple Photo Gallery I’ve built a simple photo gallery on the ASP.NET MVC framework.

In this post, we’re going to continue that project by adding paging rather than showing all of the pictures on the one page.

Adding Paging to the Model with LINQ

Since we are simply using an XML file for the storage, we need to do the paging manually against our set of objects that we have in memory. This method works well any time you have client side caching as well.

public class ImageModel : List<Image>
{
    public ImageModel() : this(1, 10)
    {
    }

    private List<Image> GetAllImages()
    {
        string imagesDir = HttpContext.Current.Server.MapPath("~/images/");
        XDocument imageMetaData = XDocument.Load(imagesDir + @"/ImageMetaData.xml");
        var images = from image in imageMetaData.Descendants("image")
                     select new Image(image.Element("filename").Value,
                     image.Element("description").Value);
        
        TotalCount = images.Count<Image>();

        return images.ToList<Image>();
    }

    public int TotalCount { get; set; }
    public int CurrentPage { get; set; }
    public int PageSize { get; set; }
    public ImageModel(int pageNum, int pageSize)
    {
        CurrentPage = pageNum;
        PageSize = pageSize;

        var images = GetAllImages();

        this.AddRange(images.Skip((pageNum - 1) * 
            pageSize).Take(pageSize).ToList());
    }
}

Notice that I added a new constructor that takes as parameters page number and page size. This will allow us, from the controller, to control the action happening here. The next thing to notice is that the default constructor is now calling the new constructor passing in default parameters of 1 and 10. Notice that we’re starting with 1 instead of 0. This will make a ton more sense to the user and makes mapping the pages a lot simpler. Lastly, notice that we’re setting some parameters (TotalCount, CurrentPage and PageSize). We’ll use these in the view in a little bit.

If we run right now, we’ll only get the first 10 pictures. If you happen to be following along and coding this with me, go ahead and try it.

Adding the Custom Route

Next, we need to add a route to handle the page mechanism.

In the global.asax.cs file, in the method called RegisterRoutes add the following route.

routes.MapRoute(
    "ImagePaging",                                              // Route name
    "{controller}/Page{pagenumber}",                           // URL with parameters
    new { controller = "Home", action = "Page", pagenumber = "1" }  // Parameter defaults
);

Notice how the routes are built. It’s a series of url parts and named parameters. For example, the Page2 is going to pass in 2 as the selected pagenumber. We actually could have hard coded the whole path except for the page number.

Adding the Paging Action to the Controller

Now that we’ve got data routing to the an Action, we need to make sure that we’re handling it.

Turns out, this was the easiest piece of all.

public ActionResult Page(string pagenumber)
{
    ImageModel model = new ImageModel(int.Parse(pagenumber), 10);
    return View("index", model);
}

Notice that we are just creating the ImageModel leveraging our new constructor and passing it into a view. The view that we’re using is still the index view, which is the default. We don’t have to go build a new view for the paging, we just need to alter the data that we’re passing into our current view.

If you want, you can go test by browsing to /image/page2 and see what it shows.

Adding the Navigation Links

The last thing to do is to add the navigation links to the view. If you use the <% %> tags in any ASPX it runs on the server side. What this is actually doing is that the ASPX page is parsed and generated into code and compiled into a .NET assembly on the server side and the code inside the <% %> just gets copied into that generated code before it’s compiled. This means that the code that’s inside your brackets must match the language that you set at the top of the page.

<%if (ViewData.Model.TotalCount > ViewData.Model.PageSize){ %>
<div class="paging">
    <%if (ViewData.Model.CurrentPage > 1) { %>
        <%= Html.ActionLink("Back", 
"Page" +
(ViewData.Model.CurrentPage - 1).ToString(), "Image")%>&nbsp; <% }%> <%decimal numberOfPages =
decimal.Divide(ViewData.Model.TotalCount, ViewData.Model.PageSize); int lastPageNumber = (int)decimal.Ceiling(numberOfPages); for (int i = 1; i <= lastPageNumber; i++) { if (i != ViewData.Model.CurrentPage) { %> <%= Html.ActionLink(i.ToString(), "Page" + i.ToString(), "Image")%>&nbsp; <% } }%> <%if (ViewData.Model.CurrentPage < lastPageNumber) { %> <%= Html.ActionLink("Next",
"Page" + (ViewData.Model.CurrentPage + 1).ToString(), "Image")%> <% }%> <%=lastPageNumber%> </div> <% }%>

Notice that we’re using the properties set by back in the model here. There’s three different sections here. The first checks to see if we need a back button. The second loops over the pages and creates step links. And the third checks to see if we need a next button.

The navigation links in the view turned out to be the most complicated part of adding paging to the photo gallery.

Stay tuned to future posts for styling with CSS, adding a Silverlight front end and more.