GridView:使用泛型和 C# 可空类型 GetValueOrDefault() 进行排序和分页






4.31/5 (9投票s)
本文演示了与 IList 集合一起使用时,可空数据类型的排序机制。
引言
撰写本文的目的是为了克服与集合中存在空值时的排序相关的问题。最近我正在使用 GridView 控件,并且我正在使用泛型集合列表作为其数据源。在解决这个问题的同时,我开发了一个很好的功能,我确信这将有助于你们大多数人的开发活动。
可用功能
GridView 中包含的功能如下
问题陈述
我的数据库表中有可空值字段数据类型。因此我在我的 asp.net 代码中使用了 C# 的可空数据类型。这样做我遇到了 IComparer 的排序失败问题。经过一些研究和开发,我想出了解决方案。我使用 GetValueOrDefault() 来解决这个问题。我如何将它应用到我的解决方案如下所示。
考虑数据库表模式如下Column | DataType | 可空值 |
CountryID | Int | 否 |
CountryName | 字符串 | 否 |
CountryTradeCode | Int | 是 |
实现 IComparer:业务实体类 Country
在下面的类中,我们有如上所述的三个字段。在这里,我们有 m_CountryTradeCode 作为可空数据类型。我面临着排序可空数据类型的问题。所以我得到了一个解决方法,如下所示。
case CountryComparer.CountryComparisonType.CountryTradeCode: return this.m_CountryTradeCode.GetValueOrDefault().CompareTo(rhs.m_CountryTradeCode.GetValueOrDefault());关于 IComparer 的一个重要方面是,它对完整的 Class 对象进行操作,并且它了解对象元素,而 IComparable 仅对对象的元素进行操作。完整的类如下所示。
public class Country
{
private int m_CountryID = int.MinValue;
private string m_CountryName = string.Empty;
private int? m_CountryTradeCode = null;
public Country()
{
}
public Country(int countryID)
{
m_CountryID = countryID;
}
public Country(int countryID, string countryName, int? countryTradeCode)
: this(countryID)
{
m_CountryName = countryName;
m_CountryTradeCode = countryTradeCode;
}
public int CountryID
{
get { return m_CountryID; }
set { m_CountryID = value; }
}
public int? CountryTradeCode
{
get { return m_CountryTradeCode; }
set { m_CountryTradeCode = value; }
}
public string CountryName
{
get { return m_CountryName; }
set { m_CountryName = value; }
}
public int CompareTo(Country rhs, Country.CountryComparer.CountryComparisonType which)
{
switch (which)
{
case CountryComparer.CountryComparisonType.CountryID:
return this.m_CountryID.CompareTo(rhs.m_CountryID);
case CountryComparer.CountryComparisonType.CountryName:
return this.m_CountryName.CompareTo(rhs.m_CountryName);
case CountryComparer.CountryComparisonType.CountryTradeCode:
return this.m_CountryTradeCode.
GetValueOrDefault().CompareTo(rhs.m_CountryTradeCode.GetValueOrDefault());
}
return 0;
}
public class CountryComparer : IComparer< Country >
{
public enum CountryComparisonType
{
CountryID,
CountryName,
CountryTradeCode,
NULL
}
private CountryComparisonType _whichComparison;
private Utility.SortOrder _sortDirection;
public CountryComparisonType WhichComparison
{
get { return _whichComparison; }
set { _whichComparison = value; }
}
public int Compare(Country lhs, Country rhs)
{
if (SortDirection == Utility.SortOrder.Asc)
return lhs.CompareTo(rhs, WhichComparison);
else
return rhs.CompareTo(lhs, WhichComparison);
}
public bool Equals(Country lhs, Country rhs)
{
return this.Compare(lhs, rhs) == 0;
}
public int GetHashCode(Country e)
{
return e.GetHashCode();
}
public Utility.SortOrder SortDirection
{
get { return _sortDirection; }
set { _sortDirection = value; }
}
}
}
使用 Country 对象填充集合列表
可以使用 datareader 从数据库获取此数据,并且可以按如下所示填充此集合列表。为了方便解决方案,我没有使用数据库,而是对这些值进行了硬编码以方便理解。如果你注意到,在作为记录添加到集合列表中的对象中存在空字段。这里的重要挑战是对这个包含空值字段的集合列表进行排序。可空类型仅应用于值类型。由于空引用未分配给值类型,因此 C# 可空数据类型提供了此功能。例如。 int a=null; 在 C# 中是不允许的。这可以通过可空数据类型来克服,上面的例子可以重写为可空类型:int? a = null;
private IList GetCountryList()
{
IList < Country > countryList = new List < Country >();
countryList.Add(new Country(1, "United States Of America", 100001));
countryList.Add(new Country(2, "Africa", null));
countryList.Add(new Country(3, "India", null));
countryList.Add(new Country(4, "Singapore", 100004));
countryList.Add(new Country(5, "Newzealand", 100005));
countryList.Add(new Country(6, "United Kingdom", 100006));
countryList.Add(new Country(7, "Australia", 100007));
countryList.Add(new Country(8, "China", 100008));
countryList.Add(new Country(9, "Malaysia", null));
countryList.Add(new Country(10, "Germany", 100011));
countryList.Add(new Country(11, "France", 100009));
countryList.Add(new Country(12, "United States Of Soviet Russia", null));
return countryList;
}
C# 泛型方法:绑定 GridView 控件
private void BindGrid < T >(T list)
{
gridCountry.DataSource = list;
gridCountry.DataBind();
}
排序事件逻辑
private void SortCountryList(Country.CountryComparer.CountryComparisonType sortExpression)
{
List < Country > countryList = (List < Country >)GetCountryList();
Country.CountryComparer countryComparer = new Country.CountryComparer();
if (Country.CountryComparer.CountryComparisonType.NULL != sortExpression)
{
if (sortExpression == SortColumn)
{
if (SortDirection == Utility.SortOrder.Asc)
{
SortDirection = Utility.SortOrder.Desc;
}
else
{
SortDirection = Utility.SortOrder.Asc;
}
}
else
{
SortDirection = Utility.SortOrder.Asc;
}
SortColumn = sortExpression;
}
countryComparer.WhichComparison = SortColumn;
countryComparer.SortDirection = SortDirection;
countryList.Sort(countryComparer);
CountryDataSource = countryList;
}
网格上的并发分页和排序操作
与标题暗示的相反,这里的分页和排序操作不是同时发生的。程序流程表明,在执行分页操作时,必须保持网格中给定列的排序顺序。这意味着分页是在已排序的列表上执行的。为此,我使用了 Viewstate 来维护当前操作。
private Country.CountryComparer.CountryComparisonType SortColumn
{
get { return (Country.CountryComparer.CountryComparisonType)ViewState["SORT_EXP"]; }
set { ViewState["SORT_EXP"] = value; }
}
private Utility.SortOrder SortDirection
{
get { return (Utility.SortOrder)ViewState["SORT_ORDER"]; }
set { ViewState["SORT_ORDER"] = value; }
}
最初,列表以当前的排序顺序和排序方向加载。
protected void Page_Load(object sender, EventArgs e)
{
try
{
if (IsPostBack == false)
{
SortColumn = Country.CountryComparer.CountryComparisonType.CountryID;
SortDirection = Utility.SortOrder.Asc;
LoadCountryList();
}
}
catch (Exception ex)
{
throw ex;
}
}
private void LoadCountryList()
{
SortCountryList(Country.CountryComparer.CountryComparisonType.NULL);
}
这是在已排序列表的页面更改事件中调用的。
private void PagingCountryList()
{
SortCountryList(Country.CountryComparer.CountryComparisonType.NULL);
}
可以下载代码并检查代码以了解更多信息和使用目的。
结论
希望我满足了读者的期望,也请为这篇文章投票,这将帮助我了解我投入的质量。欢迎任何建议和建议。期待您的反馈。参考文献
Icomparer:参考:http://www.ondotnet.com/pub/a/dotnet/excerpt/progcsharp4_ch09-04/index.html?page=5历史
初稿:2008 年 12 月 8 日