65.9K
CodeProject 正在变化。 阅读更多。
Home

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

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.31/5 (9投票s)

2008 年 12 月 8 日

CPOL

3分钟阅读

viewsIcon

64842

downloadIcon

737

本文演示了与 IList 集合一起使用时,可空数据类型的排序机制。

引言

撰写本文的目的是为了克服与集合中存在空值时的排序相关的问题。最近我正在使用 GridView 控件,并且我正在使用泛型集合列表作为其数据源。在解决这个问题的同时,我开发了一个很好的功能,我确信这将有助于你们大多数人的开发活动。

可用功能

GridView 中包含的功能如下

  • 使用了 C# 的泛型
  • 使用了可空数据类型
  • 使用泛型集合 IList 来绑定 GridView。
  • 使用 IComparer 接口对泛型集合 IList 进行排序。
  • 对可空数据字段的排序操作应用可空数据类型函数 GetValueOrDefault。
  • 在 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 日

  • © . All rights reserved.