PageRenderTime 45ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/trunk/SLExtensions/SLExtensions.Windows.Data/PagedCollection.cs

#
C# | 366 lines | 302 code | 64 blank | 0 comment | 40 complexity | a854f3e7a45caef59a76676fff10e25a MD5 | raw file
  1. namespace SLExtensions.Windows.Data
  2. {
  3. using System;
  4. using System.Collections;
  5. using System.Collections.Generic;
  6. using System.Collections.Specialized;
  7. using System.ComponentModel;
  8. using System.Net;
  9. using System.Linq;
  10. using System.Windows;
  11. using System.Windows.Controls;
  12. using System.Windows.Documents;
  13. using System.Windows.Ink;
  14. using System.Windows.Input;
  15. using System.Windows.Media;
  16. using System.Windows.Media.Animation;
  17. using System.Windows.Shapes;
  18. public class PagedCollection<T> : NotifyingObject, IPagedCollectionView, IEnumerable<T>, INotifyCollectionChanged
  19. {
  20. #region Fields
  21. private Action<PagedCollectionRequest> asyncLoadPage;
  22. private bool canChangePage;
  23. private bool isPageChanging;
  24. private int itemCount;
  25. private IEnumerable<T> page;
  26. private int pageIndex;
  27. private int pageSize;
  28. private int totalItemCount;
  29. #endregion Fields
  30. #region Constructors
  31. public PagedCollection(int totalItemCount, Action<PagedCollectionRequest> asyncLoadPage,
  32. IEnumerable<T> firstPage = null)
  33. {
  34. if (asyncLoadPage == null)
  35. throw new ArgumentNullException("asyncLoadPage");
  36. this.asyncLoadPage = asyncLoadPage;
  37. this.TotalItemCount = totalItemCount;
  38. pageIndex = 0;
  39. var page = firstPage != null ? firstPage.ToList() : null;
  40. this.PageSize = page != null ? page.Count : 0;
  41. this.Page = page;
  42. CanChangePage = true;
  43. }
  44. #endregion Constructors
  45. #region Events
  46. public event EventHandler<DataEventArgs<Exception>> AsyncException;
  47. event NotifyCollectionChangedEventHandler INotifyCollectionChanged.CollectionChanged
  48. {
  49. add { collectionChanged += value; }
  50. remove { collectionChanged -= value; }
  51. }
  52. public event EventHandler<EventArgs> PageChanged;
  53. public event EventHandler<PageChangingEventArgs> PageChanging;
  54. private event NotifyCollectionChangedEventHandler collectionChanged;
  55. #endregion Events
  56. #region Properties
  57. public bool CanChangePage
  58. {
  59. get { return this.canChangePage; }
  60. set
  61. {
  62. if (this.canChangePage != value)
  63. {
  64. this.canChangePage = value;
  65. this.RaisePropertyChanged(n => n.CanChangePage);
  66. }
  67. }
  68. }
  69. public bool CanMoveNext
  70. {
  71. get { return PageIndex < PageCount - 1; }
  72. }
  73. public bool CanMovePrevious
  74. {
  75. get { return PageIndex > 0; }
  76. }
  77. public bool IsPageChanging
  78. {
  79. get { return this.isPageChanging; }
  80. private set
  81. {
  82. if (this.isPageChanging != value)
  83. {
  84. this.isPageChanging = value;
  85. this.RaisePropertyChanged(n => n.IsPageChanging);
  86. }
  87. }
  88. }
  89. public int ItemCount
  90. {
  91. get { return this.itemCount; }
  92. private set
  93. {
  94. if (this.itemCount != value)
  95. {
  96. this.itemCount = value;
  97. this.RaisePropertyChanged(n => n.ItemCount);
  98. }
  99. }
  100. }
  101. public IEnumerable<T> Page
  102. {
  103. get { return this.page; }
  104. set
  105. {
  106. if (this.page != value)
  107. {
  108. this.page = value;
  109. this.RaisePropertyChanged(n => n.Page);
  110. }
  111. }
  112. }
  113. public int PageCount
  114. {
  115. get
  116. {
  117. return (int)Math.Ceiling((double)TotalItemCount / PageSize);
  118. }
  119. }
  120. public int PageIndex
  121. {
  122. get { return this.pageIndex; }
  123. private set
  124. {
  125. if (this.pageIndex != value)
  126. {
  127. this.pageIndex = value;
  128. this.RaisePropertyChanged(n => n.PageIndex);
  129. this.RaisePropertyChanged(n => n.CanMoveNext);
  130. this.RaisePropertyChanged(n => n.CanMovePrevious);
  131. }
  132. }
  133. }
  134. public int PageSize
  135. {
  136. get { return this.pageSize; }
  137. set
  138. {
  139. if (this.pageSize != value)
  140. {
  141. var itemPosition = this.pageSize * this.pageIndex;
  142. this.pageSize = value;
  143. this.RaisePropertyChanged(n => n.PageSize);
  144. this.RaisePropertyChanged(n => n.PageCount);
  145. this.RaisePropertyChanged(n => n.CanMoveNext);
  146. this.RaisePropertyChanged(n => n.CanMovePrevious);
  147. if (CanChangePage)
  148. {
  149. var pageIndex = (int)Math.Floor(itemPosition / PageSize);
  150. MoveToPage(pageIndex);
  151. }
  152. }
  153. }
  154. }
  155. public int TotalItemCount
  156. {
  157. get { return this.totalItemCount; }
  158. set
  159. {
  160. if (this.totalItemCount != value)
  161. {
  162. this.totalItemCount = value;
  163. this.RaisePropertyChanged(n => n.TotalItemCount);
  164. this.RaisePropertyChanged(n => n.PageCount);
  165. this.RaisePropertyChanged(n => n.CanMoveNext);
  166. this.RaisePropertyChanged(n => n.CanMovePrevious);
  167. }
  168. }
  169. }
  170. #endregion Properties
  171. #region Methods
  172. IEnumerator IEnumerable.GetEnumerator()
  173. {
  174. return ((IEnumerable<T>)this).GetEnumerator();
  175. }
  176. IEnumerator<T> IEnumerable<T>.GetEnumerator()
  177. {
  178. if (Page != null)
  179. return Page.GetEnumerator();
  180. return new List<T>().GetEnumerator();
  181. }
  182. public bool MoveToFirstPage()
  183. {
  184. return MoveToPage(0);
  185. }
  186. public bool MoveToLastPage()
  187. {
  188. return MoveToPage(PageCount - 1);
  189. }
  190. public bool MoveToNextPage()
  191. {
  192. if (CanMoveNext)
  193. return MoveToPage(PageIndex + 1);
  194. return false;
  195. }
  196. public bool MoveToPage(int pageIndex)
  197. {
  198. if (!CanChangePage)
  199. return false;
  200. if (IsPageChanging)
  201. return false;
  202. if (!RaisePageChanging(pageIndex))
  203. return false;
  204. IsPageChanging = true;
  205. asyncLoadPage(
  206. new PagedCollectionRequest(
  207. pageIndex * PageSize,
  208. PageSize,
  209. (result, error) =>
  210. {
  211. try
  212. {
  213. if (error != null)
  214. {
  215. if (AsyncException != null)
  216. {
  217. AsyncException(this, DataEventArgs.Create(new Exception("Failed to change page", error)));
  218. }
  219. }
  220. Page = result != null ? result.ToList() : null;
  221. PageIndex = pageIndex;
  222. RaiseCollectionChanged();
  223. RaisePageChanged();
  224. }
  225. finally
  226. {
  227. IsPageChanging = false;
  228. }
  229. }));
  230. return true;
  231. }
  232. public bool MoveToPreviousPage()
  233. {
  234. if (CanMovePrevious)
  235. return MoveToPage(PageIndex - 1);
  236. return false;
  237. }
  238. private void RaiseCollectionChanged()
  239. {
  240. if (collectionChanged != null)
  241. collectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
  242. }
  243. private void RaisePageChanged()
  244. {
  245. if (PageChanged != null)
  246. PageChanged(this, EventArgs.Empty);
  247. }
  248. private bool RaisePageChanging(int newIndex)
  249. {
  250. PageChangingEventArgs args = new PageChangingEventArgs(newIndex);
  251. if (PageChanging != null)
  252. {
  253. PageChanging(this, args);
  254. if (args.Cancel)
  255. return false;
  256. }
  257. return true;
  258. }
  259. #endregion Methods
  260. #region Nested Types
  261. public class PagedCollectionRequest
  262. {
  263. #region Fields
  264. private Action<IEnumerable<T>, Exception> callback;
  265. #endregion Fields
  266. #region Constructors
  267. public PagedCollectionRequest(int skip, int pageSize,
  268. Action<IEnumerable<T>, Exception> callback)
  269. {
  270. if (callback == null)
  271. throw new ArgumentNullException();
  272. this.PageSize = pageSize;
  273. this.Skip = skip;
  274. this.callback = callback;
  275. }
  276. #endregion Constructors
  277. #region Properties
  278. public int PageSize
  279. {
  280. get;
  281. private set;
  282. }
  283. public int Skip
  284. {
  285. get;
  286. private set;
  287. }
  288. #endregion Properties
  289. #region Methods
  290. public void PostError(Exception exception)
  291. {
  292. callback(null, exception);
  293. }
  294. public void PostResult(IEnumerable<T> result)
  295. {
  296. callback(result, null);
  297. }
  298. #endregion Methods
  299. }
  300. #endregion Nested Types
  301. }
  302. }