.NET Performance Blog

June 29, 2009

ASP.NET MVC Grid – Part 2 – Paging

Filed under: ASP.NET MVC — Eric P @ 9:08 am

For Part 2 – I implemented server side paging.Mvc_Grid_WithPaging

You can see demo here:
http://samples.entechsolutions.com/MvcGridSample/Part2

Code is available here:
http://samples.entechsolutions.com/Downloads/MvcGridSample/MvcGridSample_Part2.zip

Implementation

To add server side paging to grid I made the following changes:

1. Add page navigational controls to the View. For this I used a simple “<< >>” approach. The HTML for this was pretty straight forward.

2. Add page size control. For this task I used a drop down populated using a function on CustomerController:

html was:

<%= Html.DropDownList("pageSize", CustomerController.PageSizeSelectList(), new { onchange = "onPageSizeChange()" })%> rows per page                  

and function on CustomerController

public static SelectList PageSizeSelectList()
{
	var pageSizes = new List {"1", "2", "5", "10", "100"};
	return new SelectList(pageSizes, "Value");
}

3. Add JS code to make paging navigation and page size operational

//Set hidden variable to go to next/prev/last/first page and submit the form
function goToPage(pageIndex) {
	$("#currentPage").val(pageIndex);
	$("#gridAction").val("CurrentPageChanged");

	submitForm();
}

//Set action performed in hidden variable. When PageSize changes - PageIndex needs to be
//reset to 1. This logic will go on the server side.
function onPageSizeChange(pageIndex) {
	$("#gridAction").val("PageSizeChanged");
	submitForm();
}                   

function submitForm() {
	var form = $("#grid").parents("form:first");
	form.submit();
}    

4. Update CustomerController to perform paging using LINQ.


[AcceptVerbs(HttpVerbs.Post)]
public ActionResult List(int currentPage, int pageSize, string gridAction)
{
        //Do logic depending on what action was performed
	if (gridAction == "PageSizeChanged")
		currentPage = 1;

        //Check if there are no results.  In this case return empty list.
	IQueryable query = _customerService.GetQueryable();
	int totalRows = query.Count();
	if (totalRows==0)
		return View(new List());

	int totalPages = (int)Math.Ceiling((double)totalRows / (double)pageSize);
	if (totalPages != 1)
	{
		//use LINQ to perform paging
		query = query.Skip((currentPage - 1) * pageSize)
						.Take(pageSize);
	}

        //Update ViewData collection to display pager stats and pager controls
	UpdatePagerViewData(totalPages, totalRows, currentPage, pageSize);

	List customers = query.ToList();
	return View(customers);
}

5. Cleanup CSS and table structure. This part took majority of the time. At first I was thinking of just using CSS and Divs for pager, but after having some issues with getting navigational control positioned in the middle, I decided to go with a table approach. In the end I ended up using a combination of Divs and CSS.

Observations

  • Using ViewData to pass information from Controller to View is getting heavy. I am currently passing 5-10 variables just for the pager. I think it makes sense to create data structure GridModel/Grid to hold all the variables. This approach has the following advantages:
    1. Strong typing using “if (gridModel.IsFirstPage) then ” instead of “if (bool)ViewState(“IsFirstPage”)
    2. Can keep call CustomerController.List(…) clean by using “UpdateModel(gridModel);” instead of passing more and more arguments to CustomerController.List(…);
    3. Will be able to compartmentalize Pager and Sorter using object hierarchy. For ex. GridModel.Pager.PageIndex, GridModel.Sorter.SortField, etc…
  • Noticed something weird in CSS. Using CSS class like:

    #grid #pager #navButtons table tr td .disabled {
    			color: #C0C0C0;
    			text-align: center;
    		}
    

    does not work. But if I change it to:

    #grid #pager #navButtons  .disabled {
    			color: #C0C0C0;
    			text-align: center;
    		}
    

    it will work. I wonder if CSS selectors don’t allow for matching “id tag class”.

For Part 3

In upcoming part 3, I will implement server side sorting.

Advertisements

June 25, 2009

ASP.NET MVC Grid – Part 1

Filed under: ASP.NET MVC — Eric P @ 8:29 am

I have been looking for a grid control for ASP.NET MVC. In the olden days of ASP.NET Web forms – I have been using a customized GridView which had the following features:

  1. Paging (server side)
  2. Sorting (server side)
  3. AJAX – using update panel around grid
  4. Page size
  5. External Filters
  6. Remembering the state of the Grid (page, sorting, etc…) so if user goes to page 2, clicks on “Edit” to modify one of the items and then goes back to grid – it will still be on Page 2

It looks like this:
Mvc_Grid_Old_Grid

U can see a demo of it here:
http://demos.entechsolutions.com/XWebSiteTemplate/Admin
Login: demo/demo

There are several options available for ASP.NET MVC:

1. MvcContrib Grid http://www.codeplex.com/MVCContrib/Wiki/View.aspx?title=Grid.
I really like fluent interface, but there are some issues with this control:

  • Only supports paging out of the box. If you want to add AJAX or sorting – have to do it yourself
  • Can end up with a mess of code mixed with HTML. I noticed that even with simple HTML. I think MVC should expose as much HTML as possible and only use inline code when needed. Otherwise – it would be a lot like Web Forms.
  • It doesn’t seem like the control has been updated for a while.

2. Using one of the client side grids and writing an AJAX layer for server-side paging, sorting, etc..
I have looked and jqGrid, extJs grid, flexiGrid and several others.

Each one has pluses and minuses, but one issue that I found in most, is that you are pretty much stuck with the UI they provide. There are themes and custom styles available for most, but it is extremely difficult to do any of the following

  • move the pager to a different position
  • replace the pager look from ‘<>’ to ‘1 2 3 …’
  • change the way sorting works (use up down errors instead of links or use a drop down)
  • modify how inline editing works

In most cases you will be stuck with whatever look the Grid has out of the box. In many of my projects – customer has very specific requirements about how they want the grid to look and feel, so picking one of the grids above would make it difficult to use in many circumstances.

3. Roll my own grid. This is the most flexible solution, but will probably take the most time. I am planning to use JQuery for javascript as well as any JQuery plugins that simplify client side development without restricting UI. I would like to expose as much HTML as possible to allow front end developers free reign on look and feel.

I plan to start with 6 features that I had in my ASP.NET web forms grid. I would also like to add the following features depending on how much time I have available:

  • check boxes for batch actions (like delete)
  • multi column sorting
  • hide/show columns
  • move columns around
  • provide a drop down menu in the column header (kinda like ExtJs)
  • inline row editing
  • expand row to display more information

Many of these features will be handled as separate samples (or add-ons) instead of being built-in into generic grid control.

As a first step I created a simple MVC web site and used MVC templates to create “List” and “Edit” pages.Mvc_Grid_SimpleGrid
For data I used an List of objects which will be re-created for any new user session. I plan to use LinqToObjects to perform various filtering/paging/sorting operations.

You can see the site here:
http://samples.entechsolutions.com/MvcGridSample/Part1

The code is available here:
http://samples.entechsolutions.com/Downloads/MvcGridSample/MvcGridSample_Part1.zip

The next step will be adding server side paging. Here it is in Part 2.

Blog at WordPress.com.