还世间一个真相 发表于 2024-5-22 08:58:55

自定义分页控件

自定义分页控件

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


[*]Xaml
<UserControl
    x:
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    x:Name="pagingControl"
    TextElement.FontSize="14"
    mc:Ignorable="d">
    <UserControl.Resources>
      
    </UserControl.Resources>
    <StackPanel DataContext="{Binding ElementName=pagingControl}" Orientation="Horizontal">
      <Button
            Click="Button_FirstPage_Click"
            ToolTip="首页">
            <materialDesign:PackIcon
                Width="24"
                Height="24"
                VerticalAlignment="Center"
                Kind="PageFirst" />
      </Button>
      <Button
            Margin="10,0,10,0"
            Click="Button_Previous_Click"
            ToolTip="上一页">
            <materialDesign:PackIcon
                Width="20"
                Height="20"
                VerticalAlignment="Center"
                Kind="ArrowLeftCircle" />
      </Button>
      <TextBlock VerticalAlignment="Center" Text="{Binding CurrentPageIndex}" />
      <TextBlock VerticalAlignment="Center">/</TextBlock>
      <TextBlock VerticalAlignment="Center" Text="{Binding TotalPageCount}" />
      <Button
            Width="26"
            Height="26"
            Margin="10,0,0,0"
            Click="Button_Next_Click"
            ToolTip="下一页">
            <materialDesign:PackIcon
                Width="20"
                Height="20"
                VerticalAlignment="Center"
                Kind="ArrowRightCircle" />
      </Button>
      <Button
            Margin="10,0,0,0"
            Click="Button_Last_Click"
            ToolTip="尾页">
            <materialDesign:PackIcon
                Width="24"
                Height="24"
                VerticalAlignment="Center"
                Kind="PageLast" />
      </Button>
      <TextBlock Margin="20,0,0,0" VerticalAlignment="Center">共</TextBlock>
      <TextBlock
            Margin="5,0,0,0"
            VerticalAlignment="Center"
            Text="{Binding TotalCount}" />
      <TextBlock Margin="5,0,0,0" VerticalAlignment="Center">条记录</TextBlock>
      <Separator
            Height="14"
            Margin="10,0,0,0"
            BorderThickness="0.5"
             />
      <TextBlock Margin="10,0,0,0" VerticalAlignment="Center">每页数量</TextBlock>
      <ComboBox
            MinWidth="50"
            Margin="5,0,0,0"
            VerticalContentAlignment="Center"
            ItemsSource="{Binding PagesSizes}"
            SelectedIndex="0"
            SelectedItem="{Binding CurrentPageSize}"
            SelectionChanged="ComboBox_PageSize_SelectionChanged" />
      <Separator
            Height="14"
            Margin="10,0,0,0"
            BorderThickness="0.5"
             />
      <TextBlock Margin="10,0,0,0" VerticalAlignment="Center">跳转到第</TextBlock>
      <TextBox
            Width="50"
            Margin="5,0,5,0"
            VerticalAlignment="Center"
            HorizontalContentAlignment="Center"
            Text="{Binding GotoPageIndex}" />
      <TextBlock VerticalAlignment="Center">页</TextBlock>
      <Button
            Margin="5,0,0,0"
            Click="Button_Goto_Click"
            ToolTip="跳转">
            <materialDesign:PackIcon
                Width="24"
                Height="24"
                VerticalAlignment="Center"
                Kind="ArrowRightBold" />
      </Button>
    </StackPanel>
</UserControl>

[*]C#
public partial class PagingControl : UserControl, INotifyPropertyChanged
{
    // 用于防抖、节流
    private readonly ConcurrentQueue<DateTime> _operationTime = new();

    //用于防抖、节流,拦截两次时间少于1秒的操作
    private readonly TimeSpan _ignoreOperationLessThen = TimeSpan.FromSeconds(1);

    public event EventHandler CanExecuteChanged;
    public event PropertyChangedEventHandler? PropertyChanged;

    #region 普通属性
    /// <summary>
    /// 能否执行状态
    /// </summary>
    public bool CanExecute => QueryCommand?.CanExecute(null) ?? true;
    //在load后是否立即触发命令和路由事件
    public bool LoadedTrigger { get; set; } = false;
    public ObservableCollection<int> PagesSizes { get; set; } = ;

    /// <summary>
    /// 总页数
    /// </summary>
    private int _totalPageCount;
    public int TotalPageCount
    {
      get => _totalPageCount;
      set
      {
            if (_totalPageCount != value)
            {
                _totalPageCount = value;
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(TotalPageCount)));
            }
      }
    }

    /// <summary>
    /// 跳转页码
    /// </summary>
    private int _gotoPageIndex;
    public int GotoPageIndex
    {
      get => _gotoPageIndex;
      set
      {
            if (_gotoPageIndex != value)
            {
                _gotoPageIndex = value;
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(GotoPageIndex)));
            }
      }
    }

    /// <summary>
    /// 当前页大小
    /// </summary>
    private int _currentPageSize = 15;
    public int CurrentPageSize
    {
      get => _currentPageSize;
      set
      {
            if (_currentPageSize != value)
            {
                _currentPageSize = value;
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(CurrentPageSize)));
            }
      }
    }

    /// <summary>
    /// 当前页码
    /// </summary>
    private int _currentPageIndex;
    public int CurrentPageIndex
    {
      get => _currentPageIndex;
      set
      {
            if (_currentPageIndex != value)
            {
                _currentPageIndex = value;
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(CurrentPageIndex)));
            }
      }
    }

    //用于外部绑定命令
    public ICommand PageQueryCommand { get; }
    #endregion

    #region 依赖属性
    /// <summary>
    /// 总数
    /// </summary>
    public int TotalCount
    {
      get { return (int)GetValue(TotalCountProperty); }
      set { SetValue(TotalCountProperty, value); }
    }
    public ICommand QueryCommand
    {
      get { return (ICommand)GetValue(QueryCommandProperty); }
      set { SetValue(QueryCommandProperty, value); }
    }

    public static readonly DependencyProperty TotalCountProperty =
      DependencyProperty.Register("TotalCount", typeof(int), typeof(PagingControl), new FrameworkPropertyMetadata(15, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, TotalCountChangedCallback));

    public static readonly DependencyProperty QueryCommandProperty =
      DependencyProperty.Register("QueryCommand", typeof(ICommand), typeof(PagingControl), new PropertyMetadata(null, QueryCommandChangedCallback));

    #endregion

    public static readonly RoutedEvent PagingChangedEvent = EventManager.RegisterRoutedEvent("PagingChanged", RoutingStrategy.Bubble, typeof(EventHandler<PagingChangedEventArgs>), typeof(PagingControl));

    public event RoutedEventHandler PagingChanged
    {
      add => AddHandler(PagingChangedEvent, value);
      remove => RemoveHandler(PagingChangedEvent, value);
    }

    /// <summary>
    /// 构造函数
    /// </summary>
    public PagingControl()
    {
      InitializeComponent();

      TotalCount = 0;
      GotoPageIndex = 1;
      CurrentPageIndex = 0;
      TotalPageCount = 0;

      PageQueryCommand = new PageQueryCommand(this);
    }

    static void TotalCountChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
      PagingControl pagingControl = (PagingControl)d;
      pagingControl.ReLoad((int)e.NewValue);
    }

    static void QueryCommandChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
      var command = e.NewValue as ICommand;
      if (command != null)
      {
            PagingControl pagingControl = (PagingControl)d;

            command.CanExecuteChanged -= pagingControl.Command_CanExecuteChanged;
            command.CanExecuteChanged += pagingControl.Command_CanExecuteChanged;

            if (pagingControl.LoadedTrigger)
                pagingControl.FirstPage();
      }
    }

    private void Command_CanExecuteChanged(object? sender, EventArgs e)
    {
      CanExecuteChanged?.Invoke(this, e);
      IsEnabled = QueryCommand.CanExecute(null);
    }

    #region 事件
    /// <summary>
    /// 每页大小ComboBox 变化
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void ComboBox_PageSize_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
      ReLoad(TotalCount);

      CurrentPageIndex = 1;
      OnPagingChanged(CurrentPageIndex);
      e.Handled = true;
    }

    /// <summary>
    /// 首页按钮点击事件
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void Button_FirstPage_Click(object sender, RoutedEventArgs e)
    {
      FirstPage();
      e.Handled = true;
    }

    /// <summary>
    /// 尾页按钮点击事件
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void Button_Last_Click(object sender, RoutedEventArgs e)
    {
      LastPage();
      e.Handled = true;
    }

    /// <summary>
    /// 上一页按钮点击事件
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void Button_Previous_Click(object sender, RoutedEventArgs e)
    {
      PreviousPage();
      e.Handled = true;
    }

    /// <summary>
    /// 下一页按钮点击事件
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void Button_Next_Click(object sender, RoutedEventArgs e)
    {
      NextPage();
      e.Handled = true;
    }

    /// <summary>
    /// 跳转按钮点击事件
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void Button_Goto_Click(object sender, RoutedEventArgs e)
    {
      GoToPage();
      e.Handled = true;
    }
    #endregion

    private void ReLoad(int totalCount)
    {
      TotalPageCount = (totalCount + CurrentPageSize - 1) / CurrentPageSize;

      if (TotalPageCount == 0)
            CurrentPageIndex = 0;
      else if (TotalPageCount != 0 && CurrentPageIndex == 0)
            CurrentPageIndex = 1;
    }

    private bool CheckCanExcetue()
    {
      if (_operationTime.TryDequeue(out var time))
      {
            if (DateTime.Now - time < _ignoreOperationLessThen)
                return false;
      }
      _operationTime.Enqueue(DateTime.Now);

      return CanExecute;
    }

    public void FirstPage()
    {
      if (!CheckCanExcetue()) return;

      CurrentPageIndex = 1;
      OnPagingChanged(CurrentPageIndex);
    }

    public void LastPage()
    {
      if (!CheckCanExcetue()) return;

      if (TotalPageCount == 0)
      {
            OnPagingChanged(1);
      }
      else
      {
            CurrentPageIndex = TotalPageCount;
            OnPagingChanged(CurrentPageIndex);
      }
    }

    public void NextPage()
    {
      if (!CheckCanExcetue()) return;

      if (CurrentPageIndex >= TotalPageCount)
      {
            OnPagingChanged(CurrentPageIndex);
      }
      else
      {
            CurrentPageIndex++;
            OnPagingChanged(CurrentPageIndex);
      }
    }

    public void PreviousPage()
    {
      if (!CheckCanExcetue()) return;

      if (CurrentPageIndex > TotalPageCount)
      {
            CurrentPageIndex = TotalPageCount;
      }

      if (CurrentPageIndex > 1)
      {
            CurrentPageIndex--;
            OnPagingChanged(CurrentPageIndex);
      }
      else
      {
            OnPagingChanged(1);
      }
    }

    public void GoToPage()
    {
      if (!CheckCanExcetue()) return;

      if (GotoPageIndex < 1 || GotoPageIndex > TotalPageCount)
            return;

      CurrentPageIndex = GotoPageIndex;
      OnPagingChanged(CurrentPageIndex);
    }

    private void OnPagingChanged(int pageIndex)
    {
      PagingChangedEventArgs pagingChangedEventArgs = new(PagingChangedEvent, this,
            new PagingInfo(pageIndex, CurrentPageSize));

      RaiseEvent(pagingChangedEventArgs);

      QueryCommand?.Execute(new PagingInfo(pageIndex, CurrentPageSize));
    }
}相关自定义类

public record class PagingInfo(int TargetPageIndex, int PageSize);路由事件参数

public class PagingChangedEventArgs(RoutedEvent routedEvent, object source, PagingInfo pageInfo) : RoutedEventArgs(routedEvent, source)
{
    public PagingInfo PageInfo { get; set; } = pageInfo;
}外部绑定命令(用于MVVM模式下,需要其它地方触发分页控件命令)

public class PageQueryCommand : ICommand
{
    private readonly PagingControl _pagingControl;

    public event EventHandler? CanExecuteChanged;

    public PageQueryCommand(PagingControl pagingControl)
    {
      _pagingControl = pagingControl;
      _pagingControl.CanExecuteChanged += (o, e) => CanExecuteChanged?.Invoke(o, e);
    }

    public bool CanExecute(object? parameter)
    {
      return _pagingControl?.CanExecute ?? true;
    }

    public void Execute(object? parameter)
    {
      _pagingControl.FirstPage();
    }
}Demo


[*]当点击分页控件按钮时会触发QueryCommand命令和路由事件,并传入相关参数,需要在查询完结果后将查询到的总数赋值给TotalCount以便更新UI显示的相关信息
[*]当需要外部按钮来激发查询命令时,可绑定分页控件的pageQueryCommand
<Button
    x:Name="buttonQuery"
    Margin="10,0,0,0"
    HorizontalAlignment="Stretch"
    Content="查询"
    Command="{Binding ElementName=pageControl, Path=PageQueryCommand}"/>
<customControls:PagingControl
    x:Name="pageControl"
    HorizontalAlignment="Right"
    DockPanel.Dock="Bottom"
    LoadedTrigger="False"
    QueryCommand="{Binding PageQueryCommand}"
    TotalCount="{Binding TotalCount}" />


    private async Task PageQuery(PagingInfo pagingInfo){
//通过数据库进行查询
TotalCount=查出结果数量
    }希望能给你带来帮助 --来自.net菜鸡粉丝的祝愿

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