Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

461 рядки
17 KiB

  1. using BPA.UIControl.Commons;
  2. using BPA.UIControl.Commons.KnownBoxes;
  3. using BPA.UIControl.Models;
  4. using Microsoft.VisualBasic;
  5. using System;
  6. using System.Collections;
  7. using System.Collections.Generic;
  8. using System.Collections.ObjectModel;
  9. using System.ComponentModel;
  10. using System.Diagnostics.CodeAnalysis;
  11. using System.Linq;
  12. using System.Windows;
  13. using System.Windows.Controls;
  14. using System.Windows.Input;
  15. using System.Windows.Media;
  16. namespace BPA.UIControl
  17. {
  18. /// <summary>
  19. /// 页码条
  20. /// </summary>
  21. [StyleTypedProperty(Property = "ItemContainerStyle", StyleTargetType = typeof(PageBarItem))]
  22. public class PageBar : ItemsControl
  23. {
  24. static PageBar()
  25. {
  26. DefaultStyleKeyProperty.OverrideMetadata(typeof(PageBar), new FrameworkPropertyMetadata(typeof(PageBar)));
  27. }
  28. /// <inheritdoc/>
  29. protected override bool IsItemItsOwnContainerOverride(object item)
  30. {
  31. return item is PageBarItem;
  32. }
  33. /// <inheritdoc/>
  34. protected override DependencyObject GetContainerForItemOverride()
  35. {
  36. return new PageBarItem();
  37. }
  38. #region 命令
  39. /// <summary>
  40. /// 每页数量改变命令
  41. /// </summary>
  42. public ICommand PageSizeChangedCommand
  43. {
  44. get { return (ICommand)GetValue(PageSizeChangedCommandProperty); }
  45. set { SetValue(PageSizeChangedCommandProperty, value); }
  46. }
  47. public static readonly DependencyProperty PageSizeChangedCommandProperty =
  48. DependencyProperty.Register("PageSizeChangedCommand", typeof(ICommand), typeof(PageBar), new(default(ICommand)));
  49. /// <summary>
  50. /// 当前页改变命令
  51. /// </summary>
  52. public ICommand PageIndexChangedCommand
  53. {
  54. get { return (ICommand)GetValue(PageIndexChangedCommandProperty); }
  55. set { SetValue(PageIndexChangedCommandProperty, value); }
  56. }
  57. public static readonly DependencyProperty PageIndexChangedCommandProperty =
  58. DependencyProperty.Register("PageIndexChangedCommand", typeof(ICommand), typeof(PageBar), new(default(ICommand)));
  59. #endregion 命令
  60. #region 事件
  61. /// <summary>
  62. /// 每页数量改变事件
  63. /// </summary>
  64. public static readonly RoutedEvent PageSizeChangedEvent =
  65. EventManager.RegisterRoutedEvent("PageSizeChanged", RoutingStrategy.Bubble, typeof(RoutedPropertyChangedEventHandler<int>), typeof(PageBar));
  66. /// <summary>
  67. /// 每页数量改变事件
  68. /// </summary>
  69. public event RoutedPropertyChangedEventHandler<int> PageSizeChanged
  70. {
  71. add { AddHandler(PageSizeChangedEvent, value); }
  72. remove { RemoveHandler(PageSizeChangedEvent, value); }
  73. }
  74. /// <summary>
  75. /// 当前页改变事件
  76. /// </summary>
  77. public static readonly RoutedEvent PageIndexChangedEvent =
  78. EventManager.RegisterRoutedEvent("PageIndexChanged", RoutingStrategy.Bubble, typeof(RoutedPropertyChangedEventHandler<int>), typeof(PageBar));
  79. /// <summary>
  80. /// 当前页改变事件
  81. /// </summary>
  82. public event RoutedPropertyChangedEventHandler<int> PageIndexChanged
  83. {
  84. add { AddHandler(PageIndexChangedEvent, value); }
  85. remove { RemoveHandler(PageIndexChangedEvent, value); }
  86. }
  87. #endregion 事件
  88. #region 依赖属性
  89. /// <summary>
  90. /// 未选中颜色
  91. /// </summary>
  92. public Brush UnselectedBrush
  93. {
  94. get { return (Brush)GetValue(UnselectedBrushProperty); }
  95. set { SetValue(UnselectedBrushProperty, value); }
  96. }
  97. public static readonly DependencyProperty UnselectedBrushProperty =
  98. DependencyProperty.Register("UnselectedBrush", typeof(Brush), typeof(PageBar), new(default(Brush)));
  99. /// <summary>
  100. /// 选中颜色
  101. /// </summary>
  102. public Brush SelectedBrush
  103. {
  104. get { return (Brush)GetValue(SelectedBrushProperty); }
  105. set { SetValue(SelectedBrushProperty, value); }
  106. }
  107. public static readonly DependencyProperty SelectedBrushProperty =
  108. DependencyProperty.Register("SelectedBrush", typeof(Brush), typeof(PageBar), new(default(Brush)));
  109. /// <summary>
  110. /// 当前前景色
  111. /// </summary>
  112. public Brush SelectedForeground
  113. {
  114. get { return (Brush)GetValue(SelectedForegroundProperty); }
  115. set { SetValue(SelectedForegroundProperty, value); }
  116. }
  117. public static readonly DependencyProperty SelectedForegroundProperty =
  118. DependencyProperty.Register("SelectedForeground", typeof(Brush), typeof(PageBar), new(default(Brush)));
  119. /// <summary>
  120. /// 每页数量
  121. /// </summary>
  122. public int PageSize
  123. {
  124. get { return (int)GetValue(PageSizeProperty); }
  125. set { SetValue(PageSizeProperty, value); }
  126. }
  127. public static readonly DependencyProperty PageSizeProperty =
  128. DependencyProperty.Register("PageSize", typeof(int), typeof(PageBar),
  129. new(0, new((d, e) =>
  130. {
  131. PageBar pageBar = (PageBar)d;
  132. CheckPageSize(pageBar);
  133. pageBar.PageIndex = 1;
  134. pageBar.ReFreshPageBar();
  135. int oldValue = (int)e.OldValue;
  136. int newValue = (int)e.NewValue;
  137. RoutedPropertyChangedEventArgs<int> args = new RoutedPropertyChangedEventArgs<int>(oldValue, newValue);
  138. CollectionRefresh(pageBar);
  139. args.RoutedEvent = PageBar.PageSizeChangedEvent;
  140. pageBar.RaiseEvent(args);
  141. pageBar.PageSizeChangedCommand?.Execute(newValue);
  142. })));
  143. private static void CheckPageSize(PageBar pageBar)
  144. {
  145. if (!pageBar.PageSizeCollection.Contains(pageBar.PageSize))
  146. {
  147. pageBar.PageSize = pageBar.PageSizeCollection.FirstOrDefault();
  148. }
  149. }
  150. /// <summary>
  151. /// 每页数量集合
  152. /// </summary>
  153. [TypeConverter(typeof(PageSizeCollectionConverter))]
  154. public IEnumerable<int> PageSizeCollection
  155. {
  156. get { return (IEnumerable<int>)GetValue(PageSizeCollectionProperty); }
  157. set { SetValue(PageSizeCollectionProperty, value); }
  158. }
  159. public static readonly DependencyProperty PageSizeCollectionProperty =
  160. DependencyProperty.Register("PageSizeCollection", typeof(IEnumerable<int>), typeof(PageBar),
  161. new FrameworkPropertyMetadata(Enumerable.Range(1, 4).Select(x => x * 5), FrameworkPropertyMetadataOptions.AffectsParentMeasure, (d, e) => { CheckPageSize(d as PageBar); }));
  162. /// <summary>
  163. /// 当前页
  164. /// </summary>
  165. public int PageIndex
  166. {
  167. get { return (int)GetValue(PageIndexProperty); }
  168. set { SetValue(PageIndexProperty, value); }
  169. }
  170. public static readonly DependencyProperty PageIndexProperty =
  171. DependencyProperty.Register("PageIndex", typeof(int), typeof(PageBar),
  172. new FrameworkPropertyMetadata(1, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, new((d, e) =>
  173. {
  174. PageBar pageBar = (PageBar)d;
  175. pageBar.ReFreshPageBar();
  176. int oldValue = (int)e.OldValue;
  177. int newValue = (int)e.NewValue;
  178. RoutedPropertyChangedEventArgs<int> args = new RoutedPropertyChangedEventArgs<int>(oldValue, newValue);
  179. CollectionRefresh(pageBar);
  180. args.RoutedEvent = PageBar.PageIndexChangedEvent;
  181. pageBar.RaiseEvent(args);
  182. pageBar.PageIndexChangedCommand?.Execute(newValue);
  183. })));
  184. /// <summary>
  185. /// 总数量
  186. /// </summary>
  187. public int Total
  188. {
  189. get { return (int)GetValue(TotalProperty); }
  190. set { SetValue(TotalProperty, value); }
  191. }
  192. public static readonly DependencyProperty TotalProperty =
  193. DependencyProperty.Register("Total", typeof(int), typeof(PageBar),
  194. new FrameworkPropertyMetadata(default(int), FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, new((d, e) =>
  195. {
  196. PageBar pageBar = (PageBar)d;
  197. pageBar.ReFreshPageBar();
  198. CollectionRefresh(pageBar);
  199. })));
  200. /// <summary>
  201. /// 是否显示总数量
  202. /// </summary>
  203. public bool IsShowTotal
  204. {
  205. get { return (bool)GetValue(IsShowTotalProperty); }
  206. set { SetValue(IsShowTotalProperty, value); }
  207. }
  208. public static readonly DependencyProperty IsShowTotalProperty =
  209. DependencyProperty.Register("IsShowTotal", typeof(bool), typeof(PageBar), new(BooleanBoxes.FalseBox));
  210. /// <summary>
  211. /// 是否显示每页数量
  212. /// </summary>
  213. public bool IsShowPageSize
  214. {
  215. get { return (bool)GetValue(IsShowPageSizeProperty); }
  216. set { SetValue(IsShowPageSizeProperty, value); }
  217. }
  218. public static readonly DependencyProperty IsShowPageSizeProperty =
  219. DependencyProperty.Register("IsShowPageSize", typeof(bool), typeof(PageBar), new(BooleanBoxes.FalseBox));
  220. /// <summary>
  221. /// 子项停靠方向
  222. /// </summary>
  223. public Dock ItemsDock
  224. {
  225. get { return (Dock)GetValue(ItemsDockProperty); }
  226. set { SetValue(ItemsDockProperty, value); }
  227. }
  228. public static readonly DependencyProperty ItemsDockProperty =
  229. DependencyProperty.Register("ItemsDock", typeof(Dock), typeof(PageBar), new(Dock.Right));
  230. /// <summary>
  231. /// 子项内边距
  232. /// </summary>
  233. public Thickness ItemsPadding
  234. {
  235. get { return (Thickness)GetValue(ItemsPaddingProperty); }
  236. set { SetValue(ItemsPaddingProperty, value); }
  237. }
  238. public static readonly DependencyProperty ItemsPaddingProperty =
  239. DependencyProperty.Register("ItemsPadding", typeof(Thickness), typeof(PageBar), new(default(Thickness)));
  240. /// <summary>
  241. /// 是否圆角
  242. /// </summary>
  243. public bool IsRound
  244. {
  245. get { return (bool)GetValue(IsRoundProperty); }
  246. set { SetValue(IsRoundProperty, value); }
  247. }
  248. public static readonly DependencyProperty IsRoundProperty =
  249. DependencyProperty.Register("IsRound", typeof(bool), typeof(PageBar), new(BooleanBoxes.FalseBox));
  250. /// <summary>
  251. /// 需要分页的数据源
  252. /// </summary>
  253. public IEnumerable DataSource
  254. {
  255. get { return (IEnumerable)GetValue(DataSourceProperty); }
  256. set { SetValue(DataSourceProperty, value); }
  257. }
  258. public static readonly DependencyProperty DataSourceProperty =
  259. DependencyProperty.Register("DataSource", typeof(IEnumerable), typeof(PageBar),
  260. new PropertyMetadata(default, new PropertyChangedCallback((d, e) =>
  261. {
  262. PageBar pageBar = (PageBar)d;
  263. var res = pageBar.DataSource as ICollection;
  264. if (res != null) { pageBar.Total = res.Count; }
  265. })));
  266. /// <summary>
  267. /// 分页后的数据源
  268. /// </summary>
  269. public IEnumerable CurrentDataSource
  270. {
  271. get { return (IEnumerable)GetValue(CurrentDataSourceProperty); }
  272. set { SetValue(CurrentDataSourceProperty, value); }
  273. }
  274. public static readonly DependencyProperty CurrentDataSourceProperty =
  275. DependencyProperty.Register("CurrentDataSource", typeof(IEnumerable), typeof(PageBar),
  276. new PropertyMetadata(new ObservableCollection<object>()));
  277. #endregion 依赖属性
  278. #region 方法
  279. private static void CollectionRefresh(PageBar pageBar)
  280. {
  281. if (pageBar == null) return;
  282. int temp = pageBar.PageIndex * pageBar.PageSize;
  283. var ds = new ObservableCollection<object>();
  284. var cds = new ObservableCollection<object>();
  285. pageBar.DataSource?.Cast<object>()?.ToList()?.ForEach(item => { ds.Add(item); });
  286. if (ds != null && cds != null)
  287. {
  288. cds.Clear();
  289. for (int i = temp - pageBar.PageSize; i < temp; i++)
  290. {
  291. if (i >= 0 && i < ds.Count) cds.Add(ds[i]);
  292. }
  293. pageBar.CurrentDataSource = cds;
  294. }
  295. }
  296. //private void CollectionRefresh()
  297. //{
  298. // int temp = PageIndex * PageSize;
  299. // var ds = new ObservableCollection<object>();
  300. // var cds = new ObservableCollection<object>();
  301. // DataSource?.Cast<object>()?.ToList()?.ForEach(item => { ds.Add(item); });
  302. // if (ds != null && cds != null)
  303. // {
  304. // cds.Clear();
  305. // for (int i = temp - PageSize; i < temp; i++)
  306. // {
  307. // if (i >= 0 && i < ds.Count) cds.Add(ds[i]);
  308. // }
  309. // CurrentDataSource = cds;
  310. // }
  311. //}
  312. // 刷新页码条
  313. private void ReFreshPageBar()
  314. {
  315. List<PageItemModel> models = new List<PageItemModel>();
  316. if (PageSize == 0 || Total == 0)
  317. {
  318. this.ItemsSource = models;
  319. return;
  320. }
  321. int pageCount = (int)Math.Ceiling(Total / (PageSize * 1.0)); // 总共多少页
  322. models.Add(new PageItemModel
  323. {
  324. Content = "<",
  325. ToolTip = Application.Current.Resources["I18N_PageBar_PreviousPage"].ToString(),
  326. Value = PageIndex - 1,
  327. IsEnabled = PageIndex != 1 && pageCount != 1,
  328. Command = new BPACommand(PageNumberChanged)
  329. });
  330. models.Add(new PageItemModel
  331. {
  332. Content = 1,
  333. Value = 1,
  334. IsEnabled = true,
  335. Command = new BPACommand(PageNumberChanged)
  336. });
  337. int begin;
  338. int end;
  339. begin = PageIndex >= 6 ? PageIndex - 3 : 2; // index 大于等于 6 页就从 index-3 开始,否则 2 开始
  340. end = PageIndex + 3 >= pageCount ? pageCount - 1 : PageIndex + 3; // index+3 大于 total 就 total-1 结束,否则 index + 3
  341. // 补够按键数量
  342. if (end - begin < 6)
  343. {
  344. if (PageIndex - begin < 3)
  345. {
  346. end += 3 - (PageIndex - begin);
  347. end = end > pageCount - 1 ? pageCount - 1 : end;
  348. }
  349. else if (end - PageIndex < 3)
  350. {
  351. begin -= 3 - (end - PageIndex);
  352. begin = begin < 2 ? 2 : begin;
  353. }
  354. }
  355. for (int i = begin; i <= end; i++)
  356. {
  357. var model = new PageItemModel
  358. {
  359. Value = i,
  360. Content = i,
  361. IsEnabled = true,
  362. Command = new BPACommand(PageNumberChanged)
  363. };
  364. if (pageCount > 9)
  365. {
  366. if (i == begin && PageIndex - begin >= 3 && PageIndex > 5)
  367. {
  368. model.Value = PageIndex - 5;
  369. model.Content = "...";
  370. model.ToolTip = Application.Current.Resources["I18N_PageBar_Forward5Pages"].ToString();
  371. }
  372. else if (i == end && end - PageIndex >= 3 && pageCount - PageIndex >= 5)
  373. {
  374. model.Value = PageIndex + 5;
  375. model.Content = "...";
  376. model.ToolTip = Application.Current.Resources["I18N_PageBar_Backwards5Pages"].ToString();
  377. }
  378. }
  379. models.Add(model);
  380. }
  381. // 最后一页
  382. if (pageCount > 1)
  383. {
  384. models.Add(new PageItemModel
  385. {
  386. Content = pageCount,
  387. Value = pageCount,
  388. IsEnabled = true,
  389. Command = new BPACommand(PageNumberChanged)
  390. });
  391. }
  392. // 下一页
  393. models.Add(new PageItemModel
  394. {
  395. Content = ">",
  396. ToolTip = Application.Current.Resources["I18N_PageBar_NextPage"].ToString(),
  397. Value = PageIndex + 1,
  398. IsEnabled = PageIndex != pageCount && pageCount != 1,
  399. Command = new BPACommand(PageNumberChanged)
  400. });
  401. this.ItemsSource = models;
  402. }
  403. private void PageNumberChanged(object index)
  404. {
  405. PageIndex = (int)index;
  406. }
  407. #endregion 方法
  408. }
  409. }