• MVC学习(四)几种分页的实现(2)


      在第一种分页方式中,仅仅实现了分页,但并未有体现出MVC的优势,没有体现出泛型编程思想,尤其在数据量很大的时候,分页十分缓慢,除此之外,还没有实现很好的封装,不是一个通用方法。

      因此,我希望只要传入数据源以及页码数(采用泛型编程)便可以实现分页功能,且使用十分的方便。

      下面就讲讲我的一些理解。

      在泛型编程中,数据容器一般继承了IQueryable或者IEnumerable接口(此例中,数据源暂时继承了这两种接口)。

      为了调用方法方便,我决定对这两个接口写扩展方法。

      首先为了实现数据分页功能,我们常常需要考虑以下六个属性
      总页数(TotalPage)、总数据量(TotalCount)、当前页码(PageIndex)、

      一页显示数据多少(PageSize)以及上一页或者下一页(IsPreviousPage/IsNextPage)

      因此,基于对象属性,抽象出接口(IPageList),分页方法必须继承并实现这些属性。

      接口IPageList代码如下

     public interface IPageList
        {
            int TotalPage //总页数
            {
                get;
            }
            int TotalCount//总数量
            {
                get;
                set;
            }
    
            int PageIndex//第几页
            {
                get;
                set;
            }
    
            int PageSize//一页显示几条数据
            {
                get;
                set;
            }
    
            bool IsPreviousPage//是否上一页
            {
                get;
            }
    
            bool IsNextPage
            {
                get;
            }
        }
    IPageList

      实现接口,代码如下:

    public class PagedList<T>:List<T>:IPageList
        {
        public int TotalPage
            {
           return (int)Math.Ceiling((doubule)TotalCount/PageSize);
        }
        public int TotalCount
        {
           get; set;
        }
          public int PageIndex
            {
                get;
                set;
            }
    
            public int PageSize
            {
                get;
                set;
            }
    
        public bool IsPreviousPage
            {
           get { return (PageIndex>1); }
        }
        public bool IsNextPage
        {
           get { ((PageIndex) * PageSize) < TotalCount; }
        }
         }
    PagedList
     让我们看看这句代码" public class PagedList<T>:List<T>:IPageList ",这里我们定义了一个泛型类PagedList<T>,
    (其中T是一个关键字,T的类型可以是引用类型,也可以是值类)。在本例子,T是一个引用类型,而且是一个Model。

      首先写一个静态类,然后在这个静态类中书写静态方法。扩展方法使您能够向现有类型“添加”方法,而无需创建新的派生类型、重新编译或以其他方式修改原始类型。 扩展方法是一种特殊的静态方法,因此,扩展方法应该放在一个静态类中。

        好,首先对IQueryable<T>进行扩展,命名方法名称为 ToPagedList,一步一步的解析。

      返回值应该是一个泛型集合,因此,方法名可以这样写

          public List<T> ToPagedList<T>(this IQueryable<T> source,int? index,int? pageSize){  }

          在这里,我们可以看到,数据源的类型是IQueryable<T>,页码数index是可空类型(默认第一页),每页数据条目pageSize可空类型,默认10条数据。

      那么,如何调用这些方法的?

      初学泛型编程确实挺麻烦,思考的方式不太一样,特别是代码的写法比较特殊,如果把泛型类当做普通的类来思考,就比较容易。

      我们需要一个类的属性时,怎么去实例化呢(剔除静态类)? 很显然,new一个新的实例,然后去调用这个属性(我们写web Form页面写多了,很少考虑服务器控件是如何初始化的);如果想全部实例化属性,则需要在重载构造函数中动动手脚了。

      那么,我们需要从构造函数中得到什么呢, 这才是重点。

      第一,实例化分页的各个属性;第二,得到当前页码的数据,就这两件终级任务。

      由于我希望传入数据源以及页码数便可获得分页数据,且考虑是在Asp.net MVC中,因此,传入的数据要么是IQueryable<T>,要么是IEnumerable<T>,故完全可以充分利用已经存在的类型属性为自己服务(相信微软写出的代码运行效率不会太低)。在这里我会重载两个构造函数,因为传入的数据源的类型不同。

      我们 写上我们需要的构造函数,第一个参数:数据源,第二个参数:当前页码数,第三个参数每页显示几条数据。

      这里的数据源很重要,因为要继承IQueryable或IEnumerable接口(这里需要写两个构造函数),以便可以使用不同的数据源。

      首先看数据源是IQueryable的构造函数,代码如下 

    public PagedList(IQueryable<T> source, int? pageIndex, int? pageSize)
            {
                if (pageIndex == null) { pageIndex = 1; }//默认显示第一页数据
                if (pageSize == null) { pageSize = 10; }//默认每页显示10条数据
                this.TotalCount = source.Count();
                this.PageSize = pageSize.Value;
                this.PageIndex = pageIndex.Value;
    
                if (IsPreviousPage == false)
                {
                    pageIndex = 1;
                }
    
                if (IsNextPage == false)
                {
                    pageIndex = TotalPage;
                }
                int BeforePageIndex = pageIndex.Value - 1;
                if (BeforePageIndex < 0)
                {
                    BeforePageIndex = 0;
                }
                AddRange(source.Skip((BeforePageIndex) * pageSize.Value).Take(pageSize.Value));
                //如果Index是0会报错,不能够是负数
            } 
    public PagedList(IQueryable source, int? pageIndex, int? pageSize)

      这里其实是将某一页的数据放入了List了,因为PagedList已经继承了List。

      既然PagedList是一个List,那么实例化后返回的值便是我们需要的数据,考虑这点,前面的ToPagedList方法返回的值就需要具体一点,而不是模糊的List<T>,应该是PagedList<T>,因此,用于对IQueryable扩展,方法也应该是静态方法,修订后的方法如下

     public static class Pagination
        {
            /// <summary>
            /// 返回第几页的数据
            /// </summary>
            /// <typeparam name="T">返回的数据类型</typeparam>
            /// <param name="source">数据源,数据源需继承IQueryable接口</param>
            /// <param name="index">第几页</param>
            /// <param name="pageSize">每页显示的数据条数,默认每页显示10条数据</param>
            /// <returns></returns>
            public static PagedList<T> ToPagedList<T>(this IQueryable<T> source, int? index, int? pageSize)
            {
                return new PagedList<T>(source, index, pageSize);
            }
    }
    public static class Pagination

      分页类准备好后,就是调用了。直接看代码吧

    public ActionResult FY2(string GoFlag, string PageIndex)
            {
                int PageSize = 5;
                int TotalCount = LzsDB.MyTestPages.Count();//获得此数据表中数据记录数
                double PageCount = Math.Ceiling((double)TotalCount / (double)PageSize);//获得总页数
                int NowPageIndex = 1;
                if (!string.IsNullOrEmpty(PageIndex))
                {
                    int ErrorPageIndex = 1;
                    if (!Int32.TryParse(PageIndex, out ErrorPageIndex))//如果不能转换成整数,则默认当前页码为1
                    {
                        PageIndex = "1";
                    }
    
                    NowPageIndex = Convert.ToInt32(PageIndex);//
                }
                GoFlag = string.IsNullOrEmpty(GoFlag) ? "First" : GoFlag;
    
                switch (GoFlag)
                {
                    case "First":
                        ViewBag.P2Index = 1;
                        NowPageIndex = 1;
                        break;
                    case "Pre":
    
                        ViewBag.P2Index = Convert.ToInt32(PageIndex) - 1;
                        NowPageIndex = Convert.ToInt32(PageIndex) - 1;
    
                        break;
                    case "Next":
                        ViewBag.P2Index = Convert.ToInt32(PageIndex) + 1;
                        NowPageIndex = Convert.ToInt32(PageIndex) + 1;
    
                        break;
                    case "Last":
                        ViewBag.P2Index = PageCount;
                        NowPageIndex = Convert.ToInt32(PageCount);
                        break;
                }
    
                var MyTestPagesList = LzsDB.MyTestPages.OrderBy(a => a.Id);
                        return View(MyTestPagesList.ToPagedList(NowPageIndex, 5));
            }
    FY2(string GoFlag, string PageIndex)

       分页后的效果如下

      

      我插入了120万条数据,每页显示5条,在本机测试,分页还是蛮快的。

      

      整个源程序点此下载,本例子是vs2010,MVC3,配置好数据库便可运行。

  • 相关阅读:
    nginx的高级用法
    在windowsXP中如何配置php环境
    .net面试问答
    GridView的其他用法小总结
    php ajax 中文乱码问题解决办法(接收发送)
    SQL时间函数DateAdd的用法
    GridView选中,编辑,取消,删除
    php如何获取复选框选中的值
    C# 中对xml文件的操作
    将分享按钮加入到页面中
  • 原文地址:https://www.cnblogs.com/xianrongbin/p/3480790.html
Copyright © 2020-2023  润新知