翼度科技»论坛 编程开发 .net 查看内容

自定义分页控件

4

主题

4

帖子

12

积分

新手上路

Rank: 1

积分
12
自定义分页控件

tip: 该控件的样式用的是materialDesign库,需要下载Nuget包
Code


  • Xaml
  1. <UserControl
  2.     x:
  3.     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  4.     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  5.     xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
  6.     xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
  7.     xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
  8.     x:Name="pagingControl"
  9.     TextElement.FontSize="14"
  10.     mc:Ignorable="d">
  11.     <UserControl.Resources>
  12.         
  13.     </UserControl.Resources>
  14.     <StackPanel DataContext="{Binding ElementName=pagingControl}" Orientation="Horizontal">
  15.         <Button
  16.             Click="Button_FirstPage_Click"
  17.             ToolTip="首页">
  18.             <materialDesign:PackIcon
  19.                 Width="24"
  20.                 Height="24"
  21.                 VerticalAlignment="Center"
  22.                 Kind="PageFirst" />
  23.         </Button>
  24.         <Button
  25.             Margin="10,0,10,0"
  26.             Click="Button_Previous_Click"
  27.             ToolTip="上一页">
  28.             <materialDesign:PackIcon
  29.                 Width="20"
  30.                 Height="20"
  31.                 VerticalAlignment="Center"
  32.                 Kind="ArrowLeftCircle" />
  33.         </Button>
  34.         <TextBlock VerticalAlignment="Center" Text="{Binding CurrentPageIndex}" />
  35.         <TextBlock VerticalAlignment="Center">/</TextBlock>
  36.         <TextBlock VerticalAlignment="Center" Text="{Binding TotalPageCount}" />
  37.         <Button
  38.             Width="26"
  39.             Height="26"
  40.             Margin="10,0,0,0"
  41.             Click="Button_Next_Click"
  42.             ToolTip="下一页">
  43.             <materialDesign:PackIcon
  44.                 Width="20"
  45.                 Height="20"
  46.                 VerticalAlignment="Center"
  47.                 Kind="ArrowRightCircle" />
  48.         </Button>
  49.         <Button
  50.             Margin="10,0,0,0"
  51.             Click="Button_Last_Click"
  52.             ToolTip="尾页">
  53.             <materialDesign:PackIcon
  54.                 Width="24"
  55.                 Height="24"
  56.                 VerticalAlignment="Center"
  57.                 Kind="PageLast" />
  58.         </Button>
  59.         <TextBlock Margin="20,0,0,0" VerticalAlignment="Center">共</TextBlock>
  60.         <TextBlock
  61.             Margin="5,0,0,0"
  62.             VerticalAlignment="Center"
  63.             Text="{Binding TotalCount}" />
  64.         <TextBlock Margin="5,0,0,0" VerticalAlignment="Center">条记录</TextBlock>
  65.         <Separator
  66.             Height="14"
  67.             Margin="10,0,0,0"
  68.             BorderThickness="0.5"
  69.              />
  70.         <TextBlock Margin="10,0,0,0" VerticalAlignment="Center">每页数量</TextBlock>
  71.         <ComboBox
  72.             MinWidth="50"
  73.             Margin="5,0,0,0"
  74.             VerticalContentAlignment="Center"
  75.             ItemsSource="{Binding PagesSizes}"
  76.             SelectedIndex="0"
  77.             SelectedItem="{Binding CurrentPageSize}"
  78.             SelectionChanged="ComboBox_PageSize_SelectionChanged" />
  79.         <Separator
  80.             Height="14"
  81.             Margin="10,0,0,0"
  82.             BorderThickness="0.5"
  83.              />
  84.         <TextBlock Margin="10,0,0,0" VerticalAlignment="Center">跳转到第</TextBlock>
  85.         <TextBox
  86.             Width="50"
  87.             Margin="5,0,5,0"
  88.             VerticalAlignment="Center"
  89.             HorizontalContentAlignment="Center"
  90.             Text="{Binding GotoPageIndex}" />
  91.         <TextBlock VerticalAlignment="Center">页</TextBlock>
  92.         <Button
  93.             Margin="5,0,0,0"
  94.             Click="Button_Goto_Click"
  95.             ToolTip="跳转">
  96.             <materialDesign:PackIcon
  97.                 Width="24"
  98.                 Height="24"
  99.                 VerticalAlignment="Center"
  100.                 Kind="ArrowRightBold" />
  101.         </Button>
  102.     </StackPanel>
  103. </UserControl>
复制代码

  • C#
  1. public partial class PagingControl : UserControl, INotifyPropertyChanged
  2. {
  3.     // 用于防抖、节流
  4.     private readonly ConcurrentQueue<DateTime> _operationTime = new();
  5.     //用于防抖、节流,拦截两次时间少于1秒的操作
  6.     private readonly TimeSpan _ignoreOperationLessThen = TimeSpan.FromSeconds(1);
  7.     public event EventHandler CanExecuteChanged;
  8.     public event PropertyChangedEventHandler? PropertyChanged;
  9.     #region 普通属性
  10.     /// <summary>
  11.     /// 能否执行状态
  12.     /// </summary>
  13.     public bool CanExecute => QueryCommand?.CanExecute(null) ?? true;
  14.     //在load后是否立即触发命令和路由事件
  15.     public bool LoadedTrigger { get; set; } = false;
  16.     public ObservableCollection<int> PagesSizes { get; set; } = [15, 30, 60, 200, 500, 2000];
  17.     /// <summary>
  18.     /// 总页数
  19.     /// </summary>
  20.     private int _totalPageCount;
  21.     public int TotalPageCount
  22.     {
  23.         get => _totalPageCount;
  24.         set
  25.         {
  26.             if (_totalPageCount != value)
  27.             {
  28.                 _totalPageCount = value;
  29.                 PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(TotalPageCount)));
  30.             }
  31.         }
  32.     }
  33.     /// <summary>
  34.     /// 跳转页码
  35.     /// </summary>
  36.     private int _gotoPageIndex;
  37.     public int GotoPageIndex
  38.     {
  39.         get => _gotoPageIndex;
  40.         set
  41.         {
  42.             if (_gotoPageIndex != value)
  43.             {
  44.                 _gotoPageIndex = value;
  45.                 PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(GotoPageIndex)));
  46.             }
  47.         }
  48.     }
  49.     /// <summary>
  50.     /// 当前页大小
  51.     /// </summary>
  52.     private int _currentPageSize = 15;
  53.     public int CurrentPageSize
  54.     {
  55.         get => _currentPageSize;
  56.         set
  57.         {
  58.             if (_currentPageSize != value)
  59.             {
  60.                 _currentPageSize = value;
  61.                 PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(CurrentPageSize)));
  62.             }
  63.         }
  64.     }
  65.     /// <summary>
  66.     /// 当前页码
  67.     /// </summary>
  68.     private int _currentPageIndex;
  69.     public int CurrentPageIndex
  70.     {
  71.         get => _currentPageIndex;
  72.         set
  73.         {
  74.             if (_currentPageIndex != value)
  75.             {
  76.                 _currentPageIndex = value;
  77.                 PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(CurrentPageIndex)));
  78.             }
  79.         }
  80.     }
  81.     //用于外部绑定命令
  82.     public ICommand PageQueryCommand { get; }
  83.     #endregion
  84.     #region 依赖属性
  85.     /// <summary>
  86.     /// 总数
  87.     /// </summary>
  88.     public int TotalCount
  89.     {
  90.         get { return (int)GetValue(TotalCountProperty); }
  91.         set { SetValue(TotalCountProperty, value); }
  92.     }
  93.     public ICommand QueryCommand
  94.     {
  95.         get { return (ICommand)GetValue(QueryCommandProperty); }
  96.         set { SetValue(QueryCommandProperty, value); }
  97.     }
  98.     public static readonly DependencyProperty TotalCountProperty =
  99.         DependencyProperty.Register("TotalCount", typeof(int), typeof(PagingControl), new FrameworkPropertyMetadata(15, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, TotalCountChangedCallback));
  100.     public static readonly DependencyProperty QueryCommandProperty =
  101.         DependencyProperty.Register("QueryCommand", typeof(ICommand), typeof(PagingControl), new PropertyMetadata(null, QueryCommandChangedCallback));
  102.     #endregion
  103.     public static readonly RoutedEvent PagingChangedEvent = EventManager.RegisterRoutedEvent("PagingChanged", RoutingStrategy.Bubble, typeof(EventHandler<PagingChangedEventArgs>), typeof(PagingControl));
  104.     public event RoutedEventHandler PagingChanged
  105.     {
  106.         add => AddHandler(PagingChangedEvent, value);
  107.         remove => RemoveHandler(PagingChangedEvent, value);
  108.     }
  109.     /// <summary>
  110.     /// 构造函数
  111.     /// </summary>
  112.     public PagingControl()
  113.     {
  114.         InitializeComponent();
  115.         TotalCount = 0;
  116.         GotoPageIndex = 1;
  117.         CurrentPageIndex = 0;
  118.         TotalPageCount = 0;
  119.         PageQueryCommand = new PageQueryCommand(this);
  120.     }
  121.     static void TotalCountChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
  122.     {
  123.         PagingControl pagingControl = (PagingControl)d;
  124.         pagingControl.ReLoad((int)e.NewValue);
  125.     }
  126.     static void QueryCommandChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
  127.     {
  128.         var command = e.NewValue as ICommand;
  129.         if (command != null)
  130.         {
  131.             PagingControl pagingControl = (PagingControl)d;
  132.             command.CanExecuteChanged -= pagingControl.Command_CanExecuteChanged;
  133.             command.CanExecuteChanged += pagingControl.Command_CanExecuteChanged;
  134.             if (pagingControl.LoadedTrigger)
  135.                 pagingControl.FirstPage();
  136.         }
  137.     }
  138.     private void Command_CanExecuteChanged(object? sender, EventArgs e)
  139.     {
  140.         CanExecuteChanged?.Invoke(this, e);
  141.         IsEnabled = QueryCommand.CanExecute(null);
  142.     }
  143.     #region 事件
  144.     /// <summary>
  145.     /// 每页大小  ComboBox 变化
  146.     /// </summary>
  147.     /// <param name="sender"></param>
  148.     /// <param name="e"></param>
  149.     private void ComboBox_PageSize_SelectionChanged(object sender, SelectionChangedEventArgs e)
  150.     {
  151.         ReLoad(TotalCount);
  152.         CurrentPageIndex = 1;
  153.         OnPagingChanged(CurrentPageIndex);
  154.         e.Handled = true;
  155.     }
  156.     /// <summary>
  157.     /// 首页按钮点击事件
  158.     /// </summary>
  159.     /// <param name="sender"></param>
  160.     /// <param name="e"></param>
  161.     private void Button_FirstPage_Click(object sender, RoutedEventArgs e)
  162.     {
  163.         FirstPage();
  164.         e.Handled = true;
  165.     }
  166.     /// <summary>
  167.     /// 尾页按钮点击事件
  168.     /// </summary>
  169.     /// <param name="sender"></param>
  170.     /// <param name="e"></param>
  171.     private void Button_Last_Click(object sender, RoutedEventArgs e)
  172.     {
  173.         LastPage();
  174.         e.Handled = true;
  175.     }
  176.     /// <summary>
  177.     /// 上一页按钮点击事件
  178.     /// </summary>
  179.     /// <param name="sender"></param>
  180.     /// <param name="e"></param>
  181.     private void Button_Previous_Click(object sender, RoutedEventArgs e)
  182.     {
  183.         PreviousPage();
  184.         e.Handled = true;
  185.     }
  186.     /// <summary>
  187.     /// 下一页按钮点击事件
  188.     /// </summary>
  189.     /// <param name="sender"></param>
  190.     /// <param name="e"></param>
  191.     private void Button_Next_Click(object sender, RoutedEventArgs e)
  192.     {
  193.         NextPage();
  194.         e.Handled = true;
  195.     }
  196.     /// <summary>
  197.     /// 跳转按钮点击事件
  198.     /// </summary>
  199.     /// <param name="sender"></param>
  200.     /// <param name="e"></param>
  201.     private void Button_Goto_Click(object sender, RoutedEventArgs e)
  202.     {
  203.         GoToPage();
  204.         e.Handled = true;
  205.     }
  206.     #endregion
  207.     private void ReLoad(int totalCount)
  208.     {
  209.         TotalPageCount = (totalCount + CurrentPageSize - 1) / CurrentPageSize;
  210.         if (TotalPageCount == 0)
  211.             CurrentPageIndex = 0;
  212.         else if (TotalPageCount != 0 && CurrentPageIndex == 0)
  213.             CurrentPageIndex = 1;
  214.     }
  215.     private bool CheckCanExcetue()
  216.     {
  217.         if (_operationTime.TryDequeue(out var time))
  218.         {
  219.             if (DateTime.Now - time < _ignoreOperationLessThen)
  220.                 return false;
  221.         }
  222.         _operationTime.Enqueue(DateTime.Now);
  223.         return CanExecute;
  224.     }
  225.     public void FirstPage()
  226.     {
  227.         if (!CheckCanExcetue()) return;
  228.         CurrentPageIndex = 1;
  229.         OnPagingChanged(CurrentPageIndex);
  230.     }
  231.     public void LastPage()
  232.     {
  233.         if (!CheckCanExcetue()) return;
  234.         if (TotalPageCount == 0)
  235.         {
  236.             OnPagingChanged(1);
  237.         }
  238.         else
  239.         {
  240.             CurrentPageIndex = TotalPageCount;
  241.             OnPagingChanged(CurrentPageIndex);
  242.         }
  243.     }
  244.     public void NextPage()
  245.     {
  246.         if (!CheckCanExcetue()) return;
  247.         if (CurrentPageIndex >= TotalPageCount)
  248.         {
  249.             OnPagingChanged(CurrentPageIndex);
  250.         }
  251.         else
  252.         {
  253.             CurrentPageIndex++;
  254.             OnPagingChanged(CurrentPageIndex);
  255.         }
  256.     }
  257.     public void PreviousPage()
  258.     {
  259.         if (!CheckCanExcetue()) return;
  260.         if (CurrentPageIndex > TotalPageCount)
  261.         {
  262.             CurrentPageIndex = TotalPageCount;
  263.         }
  264.         if (CurrentPageIndex > 1)
  265.         {
  266.             CurrentPageIndex--;
  267.             OnPagingChanged(CurrentPageIndex);
  268.         }
  269.         else
  270.         {
  271.             OnPagingChanged(1);
  272.         }
  273.     }
  274.     public void GoToPage()
  275.     {
  276.         if (!CheckCanExcetue()) return;
  277.         if (GotoPageIndex < 1 || GotoPageIndex > TotalPageCount)
  278.             return;
  279.         CurrentPageIndex = GotoPageIndex;
  280.         OnPagingChanged(CurrentPageIndex);
  281.     }
  282.     private void OnPagingChanged(int pageIndex)
  283.     {
  284.         PagingChangedEventArgs pagingChangedEventArgs = new(PagingChangedEvent, this,
  285.             new PagingInfo(pageIndex, CurrentPageSize));
  286.         RaiseEvent(pagingChangedEventArgs);
  287.         QueryCommand?.Execute(new PagingInfo(pageIndex, CurrentPageSize));
  288.     }
  289. }
复制代码
相关自定义类
  1. public record class PagingInfo(int TargetPageIndex, int PageSize);
复制代码
路由事件参数
  1. public class PagingChangedEventArgs(RoutedEvent routedEvent, object source, PagingInfo pageInfo) : RoutedEventArgs(routedEvent, source)
  2. {
  3.     public PagingInfo PageInfo { get; set; } = pageInfo;
  4. }
复制代码
外部绑定命令(用于MVVM模式下,需要其它地方触发分页控件命令)
  1. public class PageQueryCommand : ICommand
  2. {
  3.     private readonly PagingControl _pagingControl;
  4.     public event EventHandler? CanExecuteChanged;
  5.     public PageQueryCommand(PagingControl pagingControl)
  6.     {
  7.         _pagingControl = pagingControl;
  8.         _pagingControl.CanExecuteChanged += (o, e) => CanExecuteChanged?.Invoke(o, e);
  9.     }
  10.     public bool CanExecute(object? parameter)
  11.     {
  12.         return _pagingControl?.CanExecute ?? true;
  13.     }
  14.     public void Execute(object? parameter)
  15.     {
  16.         _pagingControl.FirstPage();
  17.     }
  18. }
复制代码
Demo


  • 当点击分页控件按钮时会触发QueryCommand命令和路由事件,并传入相关参数,需要在查询完结果后将查询到的总数赋值给TotalCount以便更新UI显示的相关信息
  • 当需要外部按钮来激发查询命令时,可绑定分页控件的pageQueryCommand
  1. <Button
  2.     x:Name="buttonQuery"
  3.     Margin="10,0,0,0"
  4.     HorizontalAlignment="Stretch"
  5.     Content="查询"
  6.     Command="{Binding ElementName=pageControl, Path=PageQueryCommand}"/>
  7. <customControls:PagingControl
  8.     x:Name="pageControl"
  9.     HorizontalAlignment="Right"
  10.     DockPanel.Dock="Bottom"
  11.     LoadedTrigger="False"
  12.     QueryCommand="{Binding PageQueryCommand}"
  13.     TotalCount="{Binding TotalCount}" />
  14. [RelayCommand]
  15.     private async Task PageQuery(PagingInfo pagingInfo){
  16. //通过数据库进行查询
  17. TotalCount=查出结果数量
  18.     }
复制代码
希望能给你带来帮助 --来自.net菜鸡粉丝的祝愿

来源:https://www.cnblogs.com/yinyuessh/p/18205496
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!

举报 回复 使用道具