MVC學習筆記八:WebGrid控件的高級使用

WebGrid控件的高級使用

在筆記三中記錄了WebGrid的簡單使用,但實際工作中並不能滿足開發要求,比如:考慮到性能,要求服務器端分頁,而不是查出所有數據來進行簡單的客戶端頁面分頁;要在排序時,給列標題顯示不同圖像等等,都不是直接就能滿足的,這裏記錄下對WebGrid進行的較高層次的使用。

一.服務器端分頁處理

在演示服務端分頁之前,先做一些簡單的準備工作:

1.新建一個空的MVC 3項目,添加一個名爲“GridController”的控制器;

2.在Model中增加一個“Movie”類;
代碼如下:
   public class Movie
    {
        //主鍵
        public int Id { get; set; }

        //電影名稱
        public string MovieName { get; set; }

        //票價
        public decimal TicketPrice { get; set; }

        //演播廳
        public string ShowAddress { get; set; }

        //上線日期
        public DateTime ShowTime { get; set; }

        //領銜主演
        public string Starring { get; set; }
    }
3.給控制器“GridController”的默認Index方法添加一個基於“Movie”的強類型視圖,支架模板選擇List;
爲方便測試,修改Index方法爲:
        public ActionResult Index()
        {
            List<Movie> movies = new List<Movie>()
            {
                new Movie(){ Id=1, MovieName="晚秋", Starring="湯唯", ShowAddress="蘇州科文中心", ShowTime=DateTime.Parse("2014-4-10 15:00:00"), TicketPrice=25.5M},
                new Movie(){ Id=2, MovieName="神偷奶爸", Starring="XXX1", ShowAddress="觀前街影城", ShowTime=DateTime.Parse("2014-5-1 14:30:00"), TicketPrice=20.5M},
                new Movie(){ Id=3, MovieName="Yes Man", Starring="XXX2", ShowAddress="蘇州印象城", ShowTime=DateTime.Parse("2014-5-2 14:25:00"), TicketPrice=21.5M},
                new Movie(){ Id=4, MovieName="里約大冒險", Starring="未知", ShowAddress="蘇州石路", ShowTime=DateTime.Parse("2014-5-3 14:40:00"), TicketPrice=22.5M},
                new Movie(){ Id=5, MovieName="瘋狂原始人", Starring="未知1", ShowAddress="觀前街影城", ShowTime=DateTime.Parse("2014-5-4 14:00:00"), TicketPrice=23.5M},
                new Movie(){ Id=6, MovieName="活着", Starring="葛優、鞏俐", ShowAddress="觀前街影城", ShowTime=DateTime.Parse("2014-5-5 14:00:00"), TicketPrice=24.5M},
                new Movie(){ Id=7, MovieName="北京遇上西雅圖", Starring="湯唯", ShowAddress="觀前街影城", ShowTime=DateTime.Parse("2014-5-6 14:00:00"), TicketPrice=26.5M},
                new Movie(){ Id=8, MovieName="人在囧途", Starring="徐崢", ShowAddress="XXX街影城", ShowTime=DateTime.Parse("2014-5-7 14:00:00"), TicketPrice=27.5M},
                new Movie(){ Id=9, MovieName="神探狄仁傑", Starring="未知", ShowAddress="觀前街影城", ShowTime=DateTime.Parse("2014-5-8 14:00:00"), TicketPrice=28.5M},
                new Movie(){ Id=10, MovieName="里約大冒險2", Starring="未知", ShowAddress="觀前街影城", ShowTime=DateTime.Parse("2014-5-9 14:00:00"), TicketPrice=29.5M},
            };

            return View(movies);
        }
4.爲了使WebGrid界面美觀一些,再添加一個CSS文件,代碼如下:
body {
}
table {  
    border: solid 1px #e8eef4;  
    border-collapse: collapse;  
}  
  
table td {  
    padding: 5px;  
    border: solid 1px #e8eef4;  
    width:100px;  
    text-align:center ;
    background-color:orange;
}  
  
table th {  
    padding: 6px 5px;  
    text-align:center;  
    background-color:#CC99CC;  
    border: solid 1px #e8eef4;  
}  

.rowStyle  
{  
    background-color: #E8E8E8;  
    color: #000;  
}  
  
.gridhead {  
        background-color:yellow;  
    font-weight:bold;  
    text-align:center;  
} 
按照原先的簡單做法,修改視圖文件代碼爲:
@model IEnumerable<MvcWebGrid.Models.Movie>
@{
    ViewBag.Title = "我的WebGrid";
}

<h2>我的WebGrid示例</h2>

@{
    var grid = new WebGrid(

        source: Model,
        
        rowsPerPage: 4

        );
        
        
}

@grid.GetHtml(
tableStyle: "table",
headerStyle: "gridhead",
mode:WebGridPagerModes.All,
firstText:"首頁",
lastText:"尾頁",
previousText:"上一頁",
nextText:"下一頁",

columns:
grid.Columns(
    grid.Column("Id", "序號"),
    grid.Column("MovieName", "電影名"),
    grid.Column("Starring", "影院地址"),
    grid.Column("TicketPrice", "票價"),
    grid.Column("ShowAddress", "影院地址"),
    grid.Column("ShowTime", "上映日期")
)
)
運行網頁,URL後加上:/grid
效果如下:

到此爲止,是以前的做法,可以在頁面進行分頁,也可以排序,但是問題來了:

如果我後臺數據量很大,假如有100萬條,在每次重新運行該網頁時,都會從數據庫中查詢出100W條數據,上面的做法只不過在客戶端頁面分頁了一下,顯示了4條,實際上我後臺卻作了查詢100W條數據的工作量,而我們也許僅僅只要看某一頁而已...

所以上面的分頁做法肯定是不能滿足性能要求的,這就要考慮使用服務端分頁。

做法很簡單,就是利用WebGrid頁(如:第n頁)和每頁需要顯示的行數(如:4行)來取數據:

舉個簡單的例子:如果我要看第1頁,那麼我只需要從數據庫中查出前1~4條數據即可;要看第2頁,只需要從數據庫中查出從5~8條數據即可,依此類推,要看第n頁,只要從數據庫中查出第(n-1)*4+1~4*n條數據即可。

接下來的問題就是考慮:如何讓數據庫去執行查詢指定行的命令,其實很簡單,不管用的是LINQ to Sql還是其它形式,無非就是在前臺查詢指令,獲得了WebGrid頁和每頁需要顯示的行數的前提下,將指令轉化成查詢指定行的SQL

SqlServer查詢指定行的SQL大家應該都知道的,如:
SELECT * FROM
(
  SELECT ROW_NUMBER() OVER( ORDER BY 排序的字段 ) AS 序號,表.* FROM 表
) tmp
WHERE tmp.序號 between xxx to xxxx
這裏不用管它,只要知道最終是轉化成這樣的SQL即可。

現在的問題就是:我要在模型綁定時,知道WebGrid頁---即用戶點擊了分頁中的哪一頁!這個十分簡單,可以利用戶點擊下一頁或上一頁時,藉助模型綁定,將webgrid頁以參數形式傳給action方法,即本例的Index方法,首先我得添加一個int型的參數:
        public ActionResult Index(int page=1)
        {
           //...
        }
其次,有了這個參數之後,後臺就知道用戶選了第幾頁,我後臺就可以根據前面的算法,算出要查詢第m~n行數據;
最後,後臺查出數據之後,返回給頁面數據,即Model,得藉助webgrid的Bind方法動態綁定數據,由於分頁還需要知道數據總行數來確定按鈕個數,所以Model裏必須要包含一個從後臺查出數據的總行數,綜上所述,我的Index視圖就不能再是綁定原先的了,以下是做法:

1)在Model文件夾增加一個類,名稱爲“SelectMovies”:
    public class SelectMovies
    {
        //根據第n頁查出的數據
        public List<Movie> selectMovies { get; set; }

        //數據總量
        public int totalCount { get; set; }

    }
2)修改Index方法爲:
     public ActionResult Index(int page=1)
        {
            const int totalCount = 10;
            const int rowsPerPage = 4;

            List<Movie> movies = new List<Movie>()
            {
                new Movie(){ Id=1, MovieName="晚秋", Starring="湯唯", ShowAddress="蘇州科文中心", ShowTime=DateTime.Parse("2014-4-10 15:00:00"), TicketPrice=25.5M},
                new Movie(){ Id=2, MovieName="神偷奶爸", Starring="XXX1", ShowAddress="觀前街影城", ShowTime=DateTime.Parse("2014-5-1 14:30:00"), TicketPrice=20.5M},
                new Movie(){ Id=3, MovieName="Yes Man", Starring="XXX2", ShowAddress="蘇州印象城", ShowTime=DateTime.Parse("2014-5-2 14:25:00"), TicketPrice=21.5M},
                new Movie(){ Id=4, MovieName="里約大冒險", Starring="未知", ShowAddress="蘇州石路", ShowTime=DateTime.Parse("2014-5-3 14:40:00"), TicketPrice=22.5M},
                new Movie(){ Id=5, MovieName="瘋狂原始人", Starring="未知1", ShowAddress="觀前街影城", ShowTime=DateTime.Parse("2014-5-4 14:00:00"), TicketPrice=23.5M},
                new Movie(){ Id=6, MovieName="活着", Starring="葛優、鞏俐", ShowAddress="觀前街影城", ShowTime=DateTime.Parse("2014-5-5 14:00:00"), TicketPrice=24.5M},
                new Movie(){ Id=7, MovieName="北京遇上西雅圖", Starring="湯唯", ShowAddress="觀前街影城", ShowTime=DateTime.Parse("2014-5-6 14:00:00"), TicketPrice=26.5M},
                new Movie(){ Id=8, MovieName="人在囧途", Starring="徐崢", ShowAddress="XXX街影城", ShowTime=DateTime.Parse("2014-5-7 14:00:00"), TicketPrice=27.5M},
                new Movie(){ Id=9, MovieName="神探狄仁傑", Starring="未知", ShowAddress="觀前街影城", ShowTime=DateTime.Parse("2014-5-8 14:00:00"), TicketPrice=28.5M},
                new Movie(){ Id=10, MovieName="里約大冒險2", Starring="未知", ShowAddress="觀前街影城", ShowTime=DateTime.Parse("2014-5-9 14:00:00"), TicketPrice=29.5M},
            };

            var result = (from ms in movies select ms).Skip((page - 1) * rowsPerPage).Take(rowsPerPage);

            SelectMovies sm = new SelectMovies()
            {
                selectMovies = result.ToList(),
                totalCount=totalCount
            };

            return View(sm);
        }
3)修改Index視圖:
@model MvcWebGrid.Models.SelectMovies

@{
    ViewBag.Title = "我的WebGrid";
}

<h2>我的WebGrid示例</h2>

@{
    var grid = new WebGrid(

        source: null,
        
        rowsPerPage: 4

        );

    grid.Bind(Model.selectMovies, rowCount: Model.totalCount, autoSortAndPage: false);
}

@grid.GetHtml(
tableStyle: "table",
headerStyle: "gridhead",
mode:WebGridPagerModes.All,
firstText:"首頁",
lastText:"尾頁",
previousText:"上一頁",
nextText:"下一頁",

columns:
grid.Columns(
    grid.Column("Id", "序號"),
    grid.Column("MovieName", "電影名"),
    grid.Column("Starring", "影院地址"),
    grid.Column("TicketPrice", "票價"),
    grid.Column("ShowAddress", "影院地址"),
    grid.Column("ShowTime", "上映日期")
)
)
編譯運行,在Index方法中加個斷點,可以看到每次供視圖綁定的新模型中,僅僅只有4條數據,而不是起初的10條:

到目前爲止,基本實現了服務端分頁,但是又存在另一個問題,那就是排序被禁用了,如果還原那將不能實現服務端分頁,接下來介紹如何在使用服務端分頁的同時還能排序。

很簡單,只要模型綁定時,給action方法提供兩個參數:一個是排序字段,一個是排序方向(正/反排序)

這裏只要修改Index方法的參數及代碼實現,不過需要通過反射實現動態排序:
      public ActionResult Index(int page=1,string sort="Id",string sortDir="ASC")
        {
            const int totalCount = 10;
            const int rowsPerPage = 4;

            List<Movie> movies = new List<Movie>()
            {
                new Movie(){ Id=1, MovieName="晚秋", Starring="湯唯", ShowAddress="蘇州科文中心", ShowTime=DateTime.Parse("2014-4-10 15:00:00"), TicketPrice=25.5M},
                new Movie(){ Id=2, MovieName="神偷奶爸", Starring="XXX1", ShowAddress="觀前街影城", ShowTime=DateTime.Parse("2014-5-1 14:30:00"), TicketPrice=20.5M},
                new Movie(){ Id=3, MovieName="Yes Man", Starring="XXX2", ShowAddress="蘇州印象城", ShowTime=DateTime.Parse("2014-5-2 14:25:00"), TicketPrice=21.5M},
                new Movie(){ Id=4, MovieName="里約大冒險", Starring="未知", ShowAddress="蘇州石路", ShowTime=DateTime.Parse("2014-5-3 14:40:00"), TicketPrice=22.5M},
                new Movie(){ Id=5, MovieName="瘋狂原始人", Starring="未知1", ShowAddress="觀前街影城", ShowTime=DateTime.Parse("2014-5-4 14:00:00"), TicketPrice=23.5M},
                new Movie(){ Id=6, MovieName="活着", Starring="葛優、鞏俐", ShowAddress="觀前街影城", ShowTime=DateTime.Parse("2014-5-5 14:00:00"), TicketPrice=24.5M},
                new Movie(){ Id=7, MovieName="北京遇上西雅圖", Starring="湯唯", ShowAddress="觀前街影城", ShowTime=DateTime.Parse("2014-5-6 14:00:00"), TicketPrice=26.5M},
                new Movie(){ Id=8, MovieName="人在囧途", Starring="徐崢", ShowAddress="XXX街影城", ShowTime=DateTime.Parse("2014-5-7 14:00:00"), TicketPrice=27.5M},
                new Movie(){ Id=9, MovieName="神探狄仁傑", Starring="未知", ShowAddress="觀前街影城", ShowTime=DateTime.Parse("2014-5-8 14:00:00"), TicketPrice=28.5M},
                new Movie(){ Id=10, MovieName="里約大冒險2", Starring="未知", ShowAddress="觀前街影城", ShowTime=DateTime.Parse("2014-5-9 14:00:00"), TicketPrice=29.5M},
            };

            IEnumerable<Movie> result;

            if (sortDir=="ASC")
            {
                 result = (from ms in movies orderby GetMovieProperty(ms, sort) ascending select ms).Skip((page - 1) * rowsPerPage).Take(rowsPerPage);
            }
            else
            {
                 result = (from ms in movies orderby GetMovieProperty(ms, sort) descending select ms).Skip((page - 1) * rowsPerPage).Take(rowsPerPage);
            }

            SelectMovies sm = new SelectMovies()
            {
                selectMovies = result.ToList(),
                totalCount=totalCount
            };

            return View(sm);
        }

        public object GetMovieProperty(object obj, string attrName)
        {
            var property = obj.GetType().GetProperty(attrName);
            object value = property.GetValue(obj, null);
            return value;
        }

以上,關於服務器分頁及排序記錄到此。



發佈了49 篇原創文章 · 獲贊 71 · 訪問量 23萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章