ASP.NET GridView ASCII 和数值排序






4.95/5 (95投票s)
使用 ASP.NET GridView 进行 ASCII 和数值排序

引言
有多少人有一个包含复杂值的列表,并且希望根据 ASCII 码和实际值对其进行排序? 我想这篇文章肯定能解决你的问题。
我将尝试基于一个简单的场景来解释解决方案。
背景
其中一个用户需求是能够对包含地块记录(包括地块号、区域代码、面积和周长以及其他属性)进行排序和查看。地块号包含一系列字符,其中可能包含字母、数字和一个或多个非字母数字字符,例如正斜杠 (/)、反斜杠 (\)、短划线 (-) 或下划线 ( _ )。
因此,排序要求是,数字前有一个字母或非字母数字字符,并且应该按数字的实际值以及其余字符进行排序。例如
- P-1054/A
- P-100/B
- P-807/A
- P-1083/A
- P-20/B
排序后将是
- P-20/B
- P-100/B
- P-807/A
- P-1054/A
- P-1083/A
问题
为了解决这个要求,让我们分别研究一下 List<T>
泛型集合类和 DataView
类的默认 Sort
方法和属性。 它们都给我们一个排序列表,但不能给出所需的结果。 如果我们对前面的示例进行排序,输出将是
- P-100/B
- P-1054/A
- P-1083/
- P-20/B
- P-807/A
解决方案
其中一个解决方案是遍历每个字符,并根据其数字、字母或特殊字符值比较其值。 因此,如果要比较的对象包含一个数字,则按数字值进行比较。 我将在下一节中解释如何执行此操作。
注意:对于本文,我将仅考虑 List<T>
类。
Using the Code
.NET 提供的内置比较接口之一是 IComparer<T>
接口,它是一个泛型类型。 在我称为 CharacterComparer<T>
的 Comparer
类中实现此接口,使我们得到一个泛型 Compare
方法。该类考虑将使用 Type T
的哪个属性来比较值。 也可以进行区分大小写的比较。 我还使用 Reflection
来获取 Type T
的属性值,以便可以轻松地进行实际的字符比较。下面显示了排序类代码的一部分
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
//
}
}
比较逻辑的核心是遍历 Type T
对象的左侧和右侧属性值的每个字符。我们还可以将其扩展以符合特定类(例如 Plot
)的每个属性(我选择此类是因为我已在本文的背景中提到了它)。
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;
}
}
}
扩展的 PlotNumberComparer
类现在将如下所示
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
//
}
}
}
让我们看看我们如何演示此比较器功能。我选择了 ASP.NET 进行演示,使用 GridView
控件。 在进入之前,让我们为 Plot
类创建一个名为 Plots
的集合类,并为 List<T>
泛型集合类创建一个名为 SortExtension
的扩展类,它将与 GridView
控件兼容。
这是 Plots
类
namespace SortDemo
{
/// <summary>
/// Plots class
/// </summary>
public class Plots : List<Plot>
{
/// <summary>
/// Plots class
/// </summary>
public Plots()
{
this.Add(new Plot("P-1054/A", 3001, null, 105.081f));
this.Add(new Plot("P-100/B", 01, 734.156f, null));
this.Add(new Plot("P-807/A", 3001, 764.277f, 111.299f));
this.Add(new Plot("P-20/B", 01, 734.156f, 108.945f));
this.Add(new Plot("P-1083/A", 3001, 198.52f, 68.108f));
}
}
}
这是 SortExtension
类
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);
}
}
}
现在到目前为止,大多数事情都做得很好。 让我们将它们放在表示层中。 在我们的表示代码类 GridViewSortDemo.aspx.cs 中,让我们放入几个方法和属性,这将使我们演示变得更容易。
以下是一些页面属性
///
/// 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;
}
}
以下是一些 private
方法
/// 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);
}
}
最后,让我们将方法 bindGridView()
调用到 Page_Load
事件
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
bindGridView();
}
现在一切都展示得很好,可以进行测试了。 只要下载功能齐全的应用程序并运行它即可。 尽情享受。 :)
历史
- 2011 年 1 月 17 日:第一个版本
- 2012 年 2 月 27 日:更新版本
- 2012 年 2 月 28 日:更新版本