Advertisement
Guest User

PagingController

a guest
Mar 14th, 2011
5,388
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 9.50 KB | None | 0 0
  1. namespace Utility
  2. {
  3.     using System;
  4.     using System.Diagnostics.Contracts;
  5.     using System.Linq;
  6.     using System.Windows.Input;
  7.  
  8.     using Microsoft.Practices.Prism.Commands;
  9.     using Microsoft.Practices.Prism.ViewModel;
  10.  
  11.     /// <summary>
  12.     /// Utility class that helps coordinate paged access to a data store.
  13.     /// </summary>
  14.     public sealed class PagingController : NotificationObject
  15.     {
  16.         /// <summary>
  17.         /// The count of items to be divided into pages.
  18.         /// </summary>
  19.         private int itemCount;
  20.  
  21.         /// <summary>
  22.         /// The current page.
  23.         /// </summary>
  24.         private int currentPage;
  25.  
  26.         /// <summary>
  27.         /// The length (number of items) of each page.
  28.         /// </summary>
  29.         private int pageSize;
  30.  
  31.         /// <summary>
  32.         /// Initializes a new instance of the <see cref="PagingController"/> class.
  33.         /// </summary>
  34.         /// <param name="itemCount">The item count.</param>
  35.         /// <param name="pageSize">The size of each page.</param>
  36.         public PagingController(int itemCount, int pageSize)
  37.         {
  38.             Contract.Requires(itemCount >= 0);
  39.             Contract.Requires(pageSize > 0);
  40.  
  41.             this.itemCount = itemCount;
  42.             this.pageSize = pageSize;
  43.             this.currentPage = this.itemCount == 0 ? 0 : 1;
  44.  
  45.             this.GotoFirstPageCommand = new DelegateCommand(() => this.CurrentPage = 1, () => this.ItemCount != 0 && this.CurrentPage > 1);
  46.             this.GotoLastPageCommand = new DelegateCommand(() => this.CurrentPage = this.PageCount, () => this.ItemCount != 0 && this.CurrentPage < this.PageCount);
  47.             this.GotoNextPageCommand = new DelegateCommand(() => ++this.CurrentPage, () => this.ItemCount != 0 && this.CurrentPage < this.PageCount);
  48.             this.GotoPreviousPageCommand = new DelegateCommand(() => --this.CurrentPage, () => this.ItemCount != 0 && this.CurrentPage > 1);
  49.         }
  50.  
  51.         /// <summary>
  52.         /// Occurs when the value of <see cref="CurrentPage"/> changes.
  53.         /// </summary>
  54.         public event EventHandler<CurrentPageChangedEventArgs> CurrentPageChanged;
  55.  
  56.         /// <summary>
  57.         /// Gets the command that, when executed, sets <see cref="CurrentPage"/> to 1.
  58.         /// </summary>
  59.         /// <value>The command that changes the current page.</value>
  60.         public ICommand GotoFirstPageCommand { get; private set; }
  61.  
  62.         /// <summary>
  63.         /// Gets the command that, when executed, decrements <see cref="CurrentPage"/> by 1.
  64.         /// </summary>
  65.         /// <value>The command that changes the current page.</value>
  66.         public ICommand GotoPreviousPageCommand { get; private set; }
  67.  
  68.         /// <summary>
  69.         /// Gets the command that, when executed, increments <see cref="CurrentPage"/> by 1.
  70.         /// </summary>
  71.         /// <value>The command that changes the current page.</value>
  72.         public ICommand GotoNextPageCommand { get; private set; }
  73.  
  74.         /// <summary>
  75.         /// Gets the command that, when executed, sets <see cref="CurrentPage"/> to <see cref="PageCount"/>.
  76.         /// </summary>
  77.         /// <value>The command that changes the current page.</value>
  78.         public ICommand GotoLastPageCommand { get; private set; }
  79.  
  80.         /// <summary>
  81.         /// Gets or sets the total number of items to be divided into pages.
  82.         /// </summary>
  83.         /// <value>The item count.</value>
  84.         public int ItemCount
  85.         {
  86.             get
  87.             {
  88.                 return this.itemCount;
  89.             }
  90.  
  91.             set
  92.             {
  93.                 Contract.Requires(value >= 0);
  94.  
  95.                 this.itemCount = value;
  96.                 this.RaisePropertyChanged(() => this.ItemCount);
  97.                 this.RaisePropertyChanged(() => this.PageCount);
  98.                 RaiseCanExecuteChanged(this.GotoLastPageCommand, this.GotoNextPageCommand);
  99.  
  100.                 if (this.CurrentPage > this.PageCount) {
  101.                     this.CurrentPage = this.PageCount;
  102.                 }
  103.             }
  104.         }
  105.  
  106.         /// <summary>
  107.         /// Gets or sets the number of items that each page contains.
  108.         /// </summary>
  109.         /// <value>The size of the page.</value>
  110.         public int PageSize
  111.         {
  112.             get
  113.             {
  114.                 return this.pageSize;
  115.             }
  116.  
  117.             set
  118.             {
  119.                 Contract.Requires(value > 0);
  120.  
  121.                 var oldStartIndex = this.CurrentPageStartIndex;
  122.                 this.pageSize = value;
  123.                 this.RaisePropertyChanged(() => this.PageSize);
  124.                 this.RaisePropertyChanged(() => this.PageCount);
  125.                 this.RaisePropertyChanged(() => this.CurrentPageStartIndex);
  126.                 RaiseCanExecuteChanged(this.GotoLastPageCommand, this.GotoNextPageCommand);
  127.  
  128.                 if (oldStartIndex >= 0) {
  129.                     this.CurrentPage = this.GetPageFromIndex(oldStartIndex);
  130.                 }
  131.             }
  132.         }
  133.  
  134.         /// <summary>
  135.         /// Gets the number of pages required to contain all items.
  136.         /// </summary>
  137.         /// <value>The page count.</value>
  138.         public int PageCount
  139.         {
  140.             get
  141.             {
  142.                 Contract.Ensures(Contract.Result<int>() == 0 || this.itemCount > 0);
  143.                 Contract.Ensures(Contract.Result<int>() > 0 || this.itemCount == 0);
  144.  
  145.                 if (this.itemCount == 0) {
  146.                     return 0;
  147.                 }
  148.  
  149.                 var ceil = (int)Math.Ceiling((double)this.itemCount / this.pageSize);
  150.  
  151.                 Contract.Assume(ceil > 0); // Math.Ceiling makes the static checker unable to prove the postcondition without help
  152.                 return ceil;
  153.             }
  154.         }
  155.  
  156.         /// <summary>
  157.         /// Gets or sets the current page.
  158.         /// </summary>
  159.         /// <value>The current page.</value>
  160.         public int CurrentPage
  161.         {
  162.             get
  163.             {
  164.                 return this.currentPage;
  165.             }
  166.  
  167.             set
  168.             {
  169.                 Contract.Requires(value == 0 || this.PageCount != 0);
  170.                 Contract.Requires(value > 0 || this.PageCount == 0);
  171.                 Contract.Requires(value <= this.PageCount);
  172.  
  173.                 this.currentPage = value;
  174.                 this.RaisePropertyChanged(() => this.CurrentPage);
  175.                 this.RaisePropertyChanged(() => this.CurrentPageStartIndex);
  176.                 RaiseCanExecuteChanged(this.GotoLastPageCommand, this.GotoNextPageCommand);
  177.                 RaiseCanExecuteChanged(this.GotoFirstPageCommand, this.GotoPreviousPageCommand);
  178.  
  179.                 var handler = this.CurrentPageChanged;
  180.                 if (handler != null) {
  181.                     handler(this, new CurrentPageChangedEventArgs(this.CurrentPageStartIndex, this.PageSize));
  182.                 }
  183.             }
  184.         }
  185.  
  186.         /// <summary>
  187.         /// Gets the index of the first item belonging to the current page.
  188.         /// </summary>
  189.         /// <value>The index of the first item belonging to the current page.</value>
  190.         public int CurrentPageStartIndex
  191.         {
  192.             get
  193.             {
  194.                 Contract.Ensures(Contract.Result<int>() == -1 || this.PageCount != 0);
  195.                 Contract.Ensures(Contract.Result<int>() >= 0 || this.PageCount == 0);
  196.                 Contract.Ensures(Contract.Result<int>() < this.ItemCount);
  197.                 return this.PageCount == 0 ? -1 : (this.CurrentPage - 1) * this.PageSize;
  198.             }
  199.         }
  200.  
  201.         /// <summary>
  202.         /// Calls RaiseCanExecuteChanged on any number of DelegateCommand instances.
  203.         /// </summary>
  204.         /// <param name="commands">The commands.</param>
  205.         [Pure]
  206.         private static void RaiseCanExecuteChanged(params ICommand[] commands)
  207.         {
  208.             Contract.Requires(commands != null);
  209.             foreach (var command in commands.Cast<DelegateCommand>()) {
  210.                 command.RaiseCanExecuteChanged();
  211.             }
  212.         }
  213.  
  214.         /// <summary>
  215.         /// Gets the number of the page to which the item with the specified index belongs.
  216.         /// </summary>
  217.         /// <param name="itemIndex">The index of the item in question.</param>
  218.         /// <returns>The number of the page in which the item with the specified index belongs.</returns>
  219.         [Pure]
  220.         private int GetPageFromIndex(int itemIndex)
  221.         {
  222.             Contract.Requires(itemIndex >= 0);
  223.             Contract.Requires(itemIndex < this.itemCount);
  224.             Contract.Ensures(Contract.Result<int>() >= 1);
  225.             Contract.Ensures(Contract.Result<int>() <= this.PageCount);
  226.  
  227.             var result = (int)Math.Floor((double)itemIndex / this.PageSize) + 1;
  228.             Contract.Assume(result >= 1); // Math.Floor makes the static checker unable to prove the postcondition without help
  229.             Contract.Assume(result <= this.PageCount); // Ditto
  230.             return result;
  231.         }
  232.  
  233.         /// <summary>
  234.         /// Defines the invariant for object of this class.
  235.         /// </summary>
  236.         [ContractInvariantMethod]
  237.         private void ObjectInvariant()
  238.         {
  239.             Contract.Invariant(this.currentPage == 0 || this.PageCount != 0);
  240.             Contract.Invariant(this.currentPage > 0 || this.PageCount == 0);
  241.             Contract.Invariant(this.currentPage <= this.PageCount);            
  242.             Contract.Invariant(this.pageSize > 0);
  243.             Contract.Invariant(this.itemCount >= 0);
  244.         }
  245.     }
  246. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement