12,890,114 members (42,595 online)
alternative version

#### Stats

35.5K views
18 bookmarked
Posted 20 Jan 2011

# ASP.NET GridView ASCII and Numeric Sorting

, 28 Feb 2012 CPOL
 Rate this:
ASCII and numeric sorting using an ASP.NET GridView

## Introduction

How many of you have a list that contains complex values and want to sort it based on ASCII code and the actual value? I would say this article will certainly solve your problem.

I will try to explain the solution based on a simple scenario.

## Background

One of users requirement was to be able to sort and view their plot records, which contains the plot number, area code, area and perimeter, and other attributes. The plot number contains a series of characters that may contain letters, numbers, and one or more non-alphanumeric characters like forward slash (/), backward slash(\), dash(-), or an underscore ( _ ).

So the sorting requirement was, a number is preceded by a letter or non-alphanumeric character, and the number should be sorted by the actual value of the number and the rest of the characters. For example:

• P-1054/A
• P-100/B
• P-807/A
• P-1083/A
• P-20/B

After sorted would be:

• P-20/B
• P-100/B
• P-807/A
• P-1054/A
• P-1083/A

## Problem

To solve this requirement, let’s investigate the default `Sort` method and property of the `List<T>` generic collection class and the `DataView` class, respectively. Both give us a sorted list, but don’t give the required result. If we sort the previous example, the output will be:

• P-100/B
• P-1054/A
• P-1083/
• P-20/B
• P-807/A

## Solution

Among one of the solutions is traversing each character and compare its value based on its number, letter, or special character value. So if the object to be compared contains a number, then compare as a number value. I will explain how to do this in the next section.

Note: For this article, I will consider only the `List<T>` class.

## Using the Code

One of the built-in comparison interfaces that .NET provides is the `IComparer<T>` interface, which is a generic type. Implementing this interface in a `Comparer `class, which I call `CharacterComparer<T>`, gives us a generic `Compare` method. The class considers which attribute of the Type `T` is going to be used for comparing the values. It is also possible to make the comparison case-sensitive. I also use `Reflection` to get the attribute value of the Type `T` so that the actual character comparison can be done easily. A portion of the sorting class code is shown below:

```namespace SortLibray
{
//
//  Full code available in the source code
//

/// <summary>
/// Character Comparer class
/// </summary>
/// <typeparam name="T">A Type T which
///         it's property is being compared</typeparam>
public class CharacterComparer<T> : IComparer<T>
{
/// <summary>
/// Compares the left and the right property values of a Type T
/// </summary>
/// <param name="left">Left value of Type T</param>
/// <param name="right">Right value of Type T</param>
/// <returns>An indicator whether the left
///         or the right is greater or not</returns>
/// <remarks></remarks>
public int Compare(T left, T right)
{
//
//  Full code available in the source code
//

// Traverse each character of the left and right values of Type T
char charLeft = leftValue[indicatorLeft];
char charRight = rightValue[indicatorRight];

// Allocate char array, based on the left and right values length of Type T
char[] spaceLeft = new char[lengthLeft];
char[] spaceRight = new char[lengthRight];
int lockerLeft = 0,lockerRight = 0;

do // Iterate each characters of the left
// value of the Type T , until you get a Digit
{
spaceLeft[lockerLeft] = charLeft;
lockerLeft = lockerLeft + 1;
indicatorLeft = indicatorLeft + 1;

if (indicatorLeft < lengthLeft)
charLeft = leftValue[indicatorLeft];
else
break;

} while (char.IsDigit(charLeft) == char.IsDigit(spaceLeft[0]));
}

//
//  Full code available in the source code
//
}
}```

The core of the comparison logic is to traverse each character of the left and right attribute values of Type `T` objects. We can also extend this to comply with each attribute of a specific class, say `Plot` (I chose this class because I already mentioned it in the background of this article).

```namespace SortDemo
{
/// <summary>
/// Plot class
/// </summary>
public class Plot
{
//
// Public Properties
//

/// <summary>
/// Plot class
/// </summary>
public Plot()
{
}

/// <summary>
/// Plot class
/// </summary>
/// <param name="plotNumber">PlotNumber value</param>
/// <param name="areaCode">AreaCode value</param>
/// <param name="area">Area value</param>
/// <param name="perimeter">Perimeter value</param>
public Plot(string plotNumber, int? areaCode,
float? area, float? perimeter)
{
this.PlotNumber = plotNumber;
this.AreaCode = areaCode;
this.Area = area;
this.Perimeter = perimeter;
}
}
}```

The extended `PlotNumberComparer` class will now look like this:

```namespace SortDemo
{
/// <summary>
/// PlotNumberComparer class
/// </summary>
public class PlotNumberComparer : CharacterComparer<Plot>
{
/// <summary>
/// PlotNumberComparter class
/// </summary>
public PlotNumberComparer()
:base("PlotNumber")
{
//
// TODO: Add constructor logic here
//
}

/// <summary>
/// PlotNumberComparter class
/// <param name="caseSensitive">Case Sensitivity indicator value</param>
/// </summary>
public PlotNumberComparer(bool caseSensitive)
: base("PlotNumber",caseSensitive)
{
//
// TODO: Add constructor logic here
//
}
}
}```

Let us see how we can demonstrate this comparer capability. I chose ASP.NET for the demo with a `GridView` control. Before going into that, let's make a collection class for the `Plot` class called `Plots` and an extension class for the `List<T>` generic collection class called `SortExtension` that will comply with the `GridView` control.

Here is the `Plots` class:

```namespace SortDemo
{
/// <summary>
/// Plots class
/// </summary>
public class Plots : List<Plot>
{
/// <summary>
/// Plots class
/// </summary>
public Plots()
{
}
}
}```

Here is the `SortExtension` class:

```namespace SortDemo
{
/// <summary>
/// SortExtension class
/// </summary>
public static class SortExtension
{
/// <summary>
/// List sort extension method
/// </summary>
/// <typeparam name="T">Type T to be sorted</typeparam>
/// <param name="genericList">Generic list to be sorted</param>
/// <param name="sortDirection">SortDirection value</param>
/// <param name="comparer">Comparer value</param>
/// <param name="caseSensitive">CaseSensitive indicator value</param>
/// <returns>Sorted list of type T</returns>
public static IList<T> SortedList<T>(this List<T> genericList,
string sortExpression, SortDirection sortDirection,
CharacterComparer<T> comparer = null, bool caseSensitive = false)
{
if (genericList == null ||
string.IsNullOrEmpty(sortExpression) ||
string.IsNullOrWhiteSpace(sortExpression))
return null;
else
{
if (comparer == null)
if (caseSensitive)
comparer = new CharacterComparer<T>(sortExpression, caseSensitive);
else
comparer = new CharacterComparer<T>(sortExpression);
else
if (caseSensitive)
if (!comparer.CaseSensitive)
comparer.CaseSensitive = caseSensitive;

genericList.Sort(comparer);
if (sortDirection == SortDirection.Descending)
genericList.Reverse();
}
return genericList;
}

/// <summary>
/// List sort extension method
/// </summary>
/// <typeparam name="T">Type T to be sorted</typeparam>
/// <param name="genericList">Generic list to be sorted</param>
/// <param name="sortDirection">SortDirection value</param>
/// <param name="comparer">Comparer value</param>
/// <param name="caseSensitive">CaseSensitive indicator value</param>
/// <returns>Sorted list of type T</returns>
public static IList<T> SortedList<T>
(this List<T> genericList, SortDirection sortDirection,
CharacterComparer<T> comparer, bool caseSensitive = false)
{
if (caseSensitive)
if (!comparer.CaseSensitive)
comparer.CaseSensitive = caseSensitive;

genericList.Sort(comparer);
if (sortDirection == SortDirection.Descending)
genericList.Reverse();
return genericList;
}

/// <summary>
/// List sort extension method
/// </summary>
/// <typeparam name="T">Type T to be sorted</typeparam>
/// <param name="genericList">Generic list to be sorted</param>
/// <param name="sortExpression">SortExpression value</param>
/// <param name="sortDirection">SortDirection value</param>
/// <param name="caseSensitive">CaseSensitive indicator value</param>
/// <returns>Sorted list of type T</returns>
public static IList<T> SortedList<T>
(this List<T> genericList, string sortExpression, SortDirection sortDirection,
bool caseSensitive = false)
{
return SortedList(genericList, sortExpression,
sortDirection, null, caseSensitive);
}
}
}```

Now most of the things have been done well so far. Let's put them in the presentation layer. In our presentation code class called GridViewSortDemo.aspx.cs, let's put a couple of methods and properties that will ease our life to present the demo.

Here are some page properties:

```///
/// Get or set GridView SortExpression in a viewstate
///
public string GridViewSortExpression
{
get
{
if (ViewState[Constants.SORT_EXPRESSION] != null)
return ViewState[Constants.SORT_EXPRESSION].ToString();
return Constants.PLOT_NUMBER; // return PlotNumber as a default expression
}
set
{
ViewState[Constants.SORT_EXPRESSION] = value;
}
}

///
/// Get or set GridView SortDirection in a viewstate
///
public SortDirection GridViewSortDirection
{
get
{
if (ViewState[Constants.SORT_DIRECTION] != null)
return (SortDirection)ViewState[Constants.SORT_DIRECTION];
return SortDirection.Ascending; // return Ascending order
}
set
{
ViewState[Constants.SORT_DIRECTION] = value;
}
}```

Here are some `private `methods:

```/// summary
/// Bind GridView to a DataSource
/// summary
private void bindGridView()
{
try
{
Plots plots = new Plots();
if (cbCharactorComparer.Checked) // Use the Character Comparer
{
if (GridViewSortExpression.ToLower().Equals(Constants.PLOT_NUMBER.ToLower()))
plots.SortedList(GridViewSortDirection,
new PlotNumberComparer(), cbCaseSensitivity.Checked);
else
plots.SortedList(GridViewSortExpression,
GridViewSortDirection, cbCaseSensitivity.Checked);
gvPlots.DataSource = plots;
gvPlots.DataBind();
}
else // Use built in Linq Sort mechanism
{
List<Plot> sortResult = plots;
switch (GridViewSortExpression)
{
case Constants.PLOT_NUMBER:
sortResult = plots.OrderBy(p => p.PlotNumber).ToList();
break;
case Constants.AREA_CODE:
sortResult = plots.OrderBy(p => p.AreaCode).ToList();
break;
case Constants.AREA:
sortResult = plots.OrderBy(p => p.Area).ToList();
break;
case Constants.PERIMETER:
sortResult = plots.OrderBy(p => p.Perimeter).ToList();
break;
default:
sortResult = plots.OrderBy(p => p.PlotNumber).ToList();
break;
}
if (GridViewSortDirection == SortDirection.Descending)
sortResult.Reverse();
gvPlots.DataSource = sortResult;
gvPlots.DataBind();
}
}
catch(Exception exception)
{
Response.Write(exception.Message);
}
}```

Finally, let’s call the method `bindGridView()` to the `Page_Load` event:

```protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
bindGridView();
}```

Now everything is presented well and ready to be tested. Just download the fully functioning application and run it. Enjoy. :)

## History

• Jan. 17, 2011: First version
• Feb. 27, 2012: Updated version
• Feb. 28, 2012: Updated version

## Share

 Architect United States
MSCS, MCTS, Senior Software Engineer, Architect, Craftsman, The Ultimate DEV ...

## You may also be interested in...

 First Prev Next
 Mis-spelled? Member 1053946022-Jan-14 5:48 Member 10539460 22-Jan-14 5:48
 My vote of 5 Akram El Assas27-Feb-12 11:26 Akram El Assas 27-Feb-12 11:26
 Re: My vote of 5 Wonde Tadesse27-Feb-12 15:45 Wonde Tadesse 27-Feb-12 15:45
 Re: My vote of 5 Akram El Assas29-Feb-12 21:17 Akram El Assas 29-Feb-12 21:17
 Good one thatraja29-Jan-12 7:18 thatraja 29-Jan-12 7:18
 Excellent ... Nanda Kumer25-May-11 7:27 Nanda Kumer 25-May-11 7:27