程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> 分享一個分頁控件的實現思路,分頁控件思路

分享一個分頁控件的實現思路,分頁控件思路

編輯:關於.NET

分享一個分頁控件的實現思路,分頁控件思路


雖然分頁控件滿天飛,因為實在沒找到WinForm程序合用的,所以就造了一回輪子。一開始認為這個事情比較簡單,沒有思考太多就開工了。事實上也沒花多少時間就寫好了第一版,想要有的功能也都實現了,以為萬事大吉。。。。。。控件的樣子長這樣:

軟件開發法則之一:如果一件事情特別順利,那麼一定會有一些坑在等著你!坑的大小和順利程度成正比。

果不其然,在前幾天的業務模塊重構時就掉分頁的坑裡面了,切換每頁行數後總是加載兩次數據。問題的原因也很簡單,加載數據的事件被觸發了兩次。靠,看來這裡業務邏輯有大問題啊!再看別的地方邏輯,也有問題!!!剛好遇到周末,於是,就開始一通全面梳理。怎麼梳理呢?還是從需求出發。

需求一:可以設置每頁顯示行數

修改了每頁顯示行數後,需要反饋到ViewModel,好根據新的顯示行數重新加載數據。等一下!似乎有的時候也不需要刷新數據吧?譬如當前每頁顯示20行,但總數只有10行,這個時候切換成每頁100行,它還是只能顯示10行啊。這個時候就不需要重新加載數據,能省就省啊。這個時候不去刷新數據,不但提高效率,體驗也更好。

需求二:可以切換頁碼,首頁|上一頁|下一頁|末頁|到[x]頁

切換頁碼後,需要反饋到ViewModel,好根據新的頁碼重新加載數據。這個直來直去的最簡單了!嗯,當前頁是首頁的時候,首頁|上一頁 這兩個按鈕應該屏蔽掉,同樣,當前頁是末頁時,下一頁|末頁 兩個按鈕也應該屏蔽掉。如果只有一頁,那麼這5個按鈕都不應該可用。

分頁的基本需求也就這兩個了,但我還需要一些特殊的需求。這些需求看上去挺簡單的,譬如:

1、新增一個對象後,將對象放到列表的最後,並且自動選中它。

2、刪除一個選定對象後,將對象從列表中移除。如果對象不是列表中最後一個對象,自動選中下一個對象,否則自動選中上一個對象(如果對象是當前頁的唯一對象,則意味著上一個對象位於上一頁,需要自動跳到上一頁)。

3、切換每頁顯示行數後還是選中當前對象,這就需要重新計算當前頁。。。。。。好吧,這裡就是大坑之所在了。到底是否需要重新加載數據呢?似乎邏輯相當復雜啊。。。。。。梳理了半天,總結出一句話:切換了頁碼或當前頁實際顯示行數變化後需要重新加載數據!

業務邏輯的梳理到這裡就完成了,接下去就是寫代碼實現的事情了。那麼,對以上業務邏輯,需要如何設計呢?

1、需要定義3個自定義事件和一個委托(因為需要通過事件傳遞參數),用於通知使用者相應參數的變化和重新加載列表數據

 1         /// <summary>  
 2         /// 每頁行數發生改變,通知修改每頁行數
 3         /// </summary>  
 4         public event EventHandler RowsPerPageChanged;
 5 
 6         /// <summary>  
 7         /// 當前頁發生改變,通知重新加載列表數據
 8         /// </summary>  
 9         public event PageControlHandle CurrentPageChanged;
10 
11         /// <summary>  
12         /// 總行數發生改變,通知修改FocusedRowHandle
13         /// </summary>  
14         public event PageControlHandle TotalRowsChanged;
15 
16         /// <summary>
17         /// 表示將處理分頁控件事件的方法
18         /// </summary>
19         /// <param name="sender"></param>
20         /// <param name="e"></param>
21         public delegate void PageControlHandle(object sender, PageControlEventArgs e);
View Code

2、需要定義5個屬性,用來傳遞參數

 1         /// <summary>
 2         /// 每頁行數下拉列表選項
 3         /// </summary>
 4         public Collection<string> RowsSelectItems
 5         {
 6             get { return _SelectItems; }
 7             set
 8             {
 9                 _SelectItems = value;
10                 cbeRows.Properties.Items.AddRange(value);
11                 cbeRows.SelectedIndex = 0;
12                 RowsPerPage = int.Parse(_SelectItems[0]);
13             }
14         }
15 
16         /// <summary>
17         /// 總行數
18         /// </summary>
19         public int TotalRows
20         {
21             set
22             {
23                 _Rows = value;
24                 _TotalPages = (int) Math.Ceiling((decimal) _Rows/RowsPerPage);
25                 Refresh();
26             }
27         }
28 
29         /// <summary>
30         /// 當前選中行Handle
31         /// </summary>
32         public int FocusedRowHandle
33         {
34             private get { return _Handle - RowsPerPage*_Current; }
35             set { _Handle = RowsPerPage*_Current + value; }
36         }
37 
38         /// <summary>
39         /// 每頁行數
40         /// </summary>
41         public int RowsPerPage { get; private set; }
42 
43         /// <summary>
44         /// 當前頁
45         /// </summary>
46         public int CurrentPage => _Current + 1;
View Code

3、需要2個Public方法,用於增加/刪除列表對象後處理相應業務邏輯

 1         /// <summary>
 2         /// 增加列表成員
 3         /// </summary>
 4         /// <param name="count">增加數量,默認1個</param>
 5         public void AddItems(int count = 1)
 6         {
 7             _Rows += count;
 8             _Handle = _Rows - 1;
 9 
10             var page = _Current;
11             Refresh();
12 
13             if (_Current > page)
14             {
15                 // 切換了頁碼需要重新加載數據
16                 CurrentPageChanged?.Invoke(this, new PageControlEventArgs(FocusedRowHandle));
17             }
18             else
19             {
20                 TotalRowsChanged?.Invoke(this, new PageControlEventArgs(FocusedRowHandle));
21             }
22         }
23 
24         /// <summary>
25         /// 減少列表成員
26         /// </summary>
27         /// <param name="count">減少數量,默認1個</param>
28         public void RemoveItems(int count = 1)
29         {
30             _Rows -= count;
31             if (_Handle >= _Rows) _Handle = _Rows - 1;
32 
33             var page = _Current;
34             Refresh();
35 
36             if (_TotalPages == 1 || _Handle < RowsPerPage*(_TotalPages - 1) || _Current < page)
37             {
38                 // 不是末頁或切換了頁碼需要重新加載數據
39                 CurrentPageChanged?.Invoke(this, new PageControlEventArgs(FocusedRowHandle));
40             }
41             else
42             {
43                 TotalRowsChanged?.Invoke(this, new PageControlEventArgs(FocusedRowHandle));
44             }
45         }
View Code

剩下的就是內部的邏輯處理函數了

 1         /// <summary>
 2         /// 切換每頁行數
 3         /// </summary>
 4         private void PageRowsChanged()
 5         {
 6             var change = RowsPerPage < _Rows - RowsPerPage*_Current;
 7             RowsPerPage = int.Parse(cbeRows.Text);
 8             RowsPerPageChanged?.Invoke(this, null);
 9 
10             var page = _Current;
11             Refresh();
12 
13             change = change || RowsPerPage < _Rows - RowsPerPage*_Current;
14             if (_Current == page && !change) return;
15 
16             // 切換了頁碼或當前頁顯示行數變化後需要重新加載數據
17             CurrentPageChanged?.Invoke(this, new PageControlEventArgs(FocusedRowHandle));
18         }
19 
20         /// <summary>
21         /// 切換當前頁
22         /// </summary>
23         /// <param name="page">頁碼</param>
24         private void ChangePage(int page)
25         {
26             _Handle = RowsPerPage*page;
27 
28             Refresh();
29 
30             CurrentPageChanged?.Invoke(this, new PageControlEventArgs(FocusedRowHandle));
31         }
32 
33         /// <summary>
34         /// 刷新控件
35         /// </summary>
36         private new void Refresh()
37         {
38             var total = _TotalPages == 0 ? 1 : _TotalPages;
39             labRows.Text = $" 行/頁 | 共 {_Rows} 行 | 分 {total} 頁";
40             labRows.Refresh();
41 
42             _Current = (int) Math.Floor((decimal) _Handle/RowsPerPage);
43             btnFirst.Enabled = _Current > 0;
44             btnPrev.Enabled = _Current > 0;
45             btnNext.Enabled = _Current < _TotalPages - 1;
46             btnLast.Enabled = _Current < _TotalPages - 1;
47             btnJump.Enabled = _TotalPages > 1;
48 
49             var width = (int) Math.Log10(_Current + 1)*7 + 18;
50             btnJump.Width = width;
51             btnJump.Text = CurrentPage.ToString();
52             labRows.Focus();
53         }
View Code

完整代碼見:https://github.com/xuanbg/Utility/tree/master/Controls

經過重構後,分頁控件對外僅暴露5個屬性和2個方法。使用者只需要在參數變化後給相應屬性賦值即可,每頁行數的調整、加載列表數據和列表的FocusedRowHandle都通過訂閱事件完成。代碼示例如下:

 1             View.TabRole.RowsPerPageChanged += (sender, args) => _PageRows = View.TabRole.RowsPerPage;
 2             View.TabRole.CurrentPageChanged += (sender, args) => PageChanged(args.RowHandle);
 3             View.TabRole.TotalRowsChanged += (sender, args) => View.GdvRole.FocusedRowHandle = args.RowHandle;
 4 
 5         /// <summary>
 6         /// 切換頁碼後重新加載角色列表
 7         /// </summary>
 8         /// <param name="handel">當前焦點行</param>
 9         private void PageChanged(int handel)
10         {
11             _CurrentPage = View.TabRole.CurrentPage;
12 
13             LoadRoles(handel);
14         }
15 
16         /// <summary>
17         /// 新增角色到角色列表
18         /// </summary>
19         /// <param name="role">RoleInfo</param>
20         internal void AddRole(RoleInfo role)
21         {
22             _Roles.Add(role);
23 
24             View.TabRole.AddItems();
25             View.GrdRole.RefreshDataSource();
26         }
27 
28         /// <summary>
29         /// 刪除當前所選角色
30         /// </summary>
31         internal void RoleDelete()
32         {
33             _Roles.Remove(Role);
34 
35             View.TabRole.RemoveItems();
36             View.GdvRole.RefreshData();
37         }
View Code

如果這篇文字對看官有點用處的話,請幫忙點下推薦,謝謝!

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved