WPF 之列表分页控件

Posted dotNET跨平台

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了WPF 之列表分页控件相关的知识,希望对你有一定的参考价值。

 WPF 之列表分页控件

控件名:WindowAcrylicBlur

作者: WPFDevelopersOrg  - 黄佳 | 驚鏵

原文链接:    https://github.com/WPFDevelopersOrg/WPFDevelopers

  • 框架使用大于等于.NET40

  • Visual Studio 2022

  • 项目使用 MIT 开源许可协议。

  • 新建Pagination自定义控件继承自Control

  • 正常模式分页 在外部套Grid分为0 - 5列:

    • Grid.Column 0 总页数共多少300条。

    • Grid.Column 1 输入每页显示多少10条。

    • Grid.Column 2 上一页按钮。

    • Grid.Column 3 所有页码按钮此处使用ListBox

    • Grid.Column 4 下一页按钮。

    • Grid.Column 5 跳转页1码输入框。

  • 精简模式分页 在外部套Grid分为0 - 9列:

    • Grid.Column 0 总页数共多少300条。

    • Grid.Column 2 输入每页显示多少10条。

    • Grid.Column 3 条 / 页

    • Grid.Column 5 上一页按钮。

    • Grid.Column 7 跳转页1码输入框。

    • Grid.Column 9 下一页按钮。

  • 每页显示跳转页码数控制只允许输入数字,不允许粘贴。

<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="10"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="10"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="5"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="5"/>
<ColumnDefinition Width="Auto"/>

1) Pagination.cs 如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using WPFDevelopers.Helpers;

namespace WPFDevelopers.Controls

    [TemplatePart(Name = CountPerPageTextBoxTemplateName, Type = typeof(TextBox))]
    [TemplatePart(Name = JustPageTextBoxTemplateName, Type = typeof(TextBox))]
    [TemplatePart(Name = ListBoxTemplateName, Type = typeof(ListBox))]
    public class Pagination : Control
    
        private const string CountPerPageTextBoxTemplateName = "PART_CountPerPageTextBox";
        private const string JustPageTextBoxTemplateName = "PART_JumpPageTextBox";
        private const string ListBoxTemplateName = "PART_ListBox";

        private const string Ellipsis = "···";
        private static readonly Type _typeofSelf = typeof(Pagination);

        private TextBox _countPerPageTextBox;
        private TextBox _jumpPageTextBox;
        private ListBox _listBox;

        static Pagination()
        
            InitializeCommands();

            DefaultStyleKeyProperty.OverrideMetadata(_typeofSelf, new FrameworkPropertyMetadata(_typeofSelf));
        

        #region Override

        public override void OnApplyTemplate()
        
            base.OnApplyTemplate();

            UnsubscribeEvents();

            _countPerPageTextBox = GetTemplateChild(CountPerPageTextBoxTemplateName) as TextBox;
            if (_countPerPageTextBox != null)
            
                _countPerPageTextBox.ContextMenu = null;
                _countPerPageTextBox.PreviewTextInput += _countPerPageTextBox_PreviewTextInput;
                _countPerPageTextBox.PreviewKeyDown += _countPerPageTextBox_PreviewKeyDown;
            

            _jumpPageTextBox = GetTemplateChild(JustPageTextBoxTemplateName) as TextBox;
            if (_jumpPageTextBox != null)
            
                _jumpPageTextBox.ContextMenu = null;
                _jumpPageTextBox.PreviewTextInput += _countPerPageTextBox_PreviewTextInput;
                _jumpPageTextBox.PreviewKeyDown += _countPerPageTextBox_PreviewKeyDown;
            

            _listBox = GetTemplateChild(ListBoxTemplateName) as ListBox;

            Init();

            SubscribeEvents();
        

        private void _countPerPageTextBox_PreviewKeyDown(object sender, KeyEventArgs e)
        
            if (Key.Space == e.Key
                ||
                Key.V == e.Key
                && e.KeyboardDevice.Modifiers == ModifierKeys.Control)
                e.Handled = true;
        

        private void _countPerPageTextBox_PreviewTextInput(object sender, TextCompositionEventArgs e)
        
            e.Handled = ControlsHelper.IsNumber(e.Text);
        

        #endregion

        #region Command

        private static void InitializeCommands()
        
            PrevCommand = new RoutedCommand("Prev", _typeofSelf);
            NextCommand = new RoutedCommand("Next", _typeofSelf);

            CommandManager.RegisterClassCommandBinding(_typeofSelf,
                new CommandBinding(PrevCommand, OnPrevCommand, OnCanPrevCommand));
            CommandManager.RegisterClassCommandBinding(_typeofSelf,
                new CommandBinding(NextCommand, OnNextCommand, OnCanNextCommand));
        

        public static RoutedCommand PrevCommand  get; private set; 

        public static RoutedCommand NextCommand  get; private set; 

        private static void OnPrevCommand(object sender, RoutedEventArgs e)
        
            var ctrl = sender as Pagination;
            ctrl.Current--;
        

        private static void OnCanPrevCommand(object sender, CanExecuteRoutedEventArgs e)
        
            var ctrl = sender as Pagination;
            e.CanExecute = ctrl.Current > 1;
        

        private static void OnNextCommand(object sender, RoutedEventArgs e)
        
            var ctrl = sender as Pagination;
            ctrl.Current++;
        

        private static void OnCanNextCommand(object sender, CanExecuteRoutedEventArgs e)
        
            var ctrl = sender as Pagination;
            e.CanExecute = ctrl.Current < ctrl.PageCount;
        

        #endregion

        #region Properties

        private static readonly DependencyPropertyKey PagesPropertyKey =
            DependencyProperty.RegisterReadOnly("Pages", typeof(IEnumerable<string>), _typeofSelf,
                new PropertyMetadata(null));

        public static readonly DependencyProperty PagesProperty = PagesPropertyKey.DependencyProperty;

        public IEnumerable<string> Pages => (IEnumerable<string>) GetValue(PagesProperty);

        private static readonly DependencyPropertyKey PageCountPropertyKey =
            DependencyProperty.RegisterReadOnly("PageCount", typeof(int), _typeofSelf,
                new PropertyMetadata(1, OnPageCountPropertyChanged));

        public static readonly DependencyProperty PageCountProperty = PageCountPropertyKey.DependencyProperty;

        public int PageCount => (int) GetValue(PageCountProperty);

        private static void OnPageCountPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        
            var ctrl = d as Pagination;
            var pageCount = (int) e.NewValue;

            /*
            if (ctrl._jumpPageTextBox != null)
                ctrl._jumpPageTextBox.Maximum = pageCount;
            */
        

        public static readonly DependencyProperty IsLiteProperty =
            DependencyProperty.Register("IsLite", typeof(bool), _typeofSelf, new PropertyMetadata(false));

        public bool IsLite
        
            get => (bool) GetValue(IsLiteProperty);
            set => SetValue(IsLiteProperty, value);
        

        public static readonly DependencyProperty CountProperty = DependencyProperty.Register("Count", typeof(int),
            _typeofSelf, new PropertyMetadata(0, OnCountPropertyChanged, CoerceCount));

        public int Count
        
            get => (int) GetValue(CountProperty);
            set => SetValue(CountProperty, value);
        

        private static object CoerceCount(DependencyObject d, object value)
        
            var count = (int) value;
            return Math.Max(count, 0);
        

        private static void OnCountPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        
            var ctrl = d as Pagination;
            var count = (int) e.NewValue;

            ctrl.SetValue(PageCountPropertyKey, (int) Math.Ceiling(count * 1.0 / ctrl.CountPerPage));
            ctrl.UpdatePages();
        

        public static readonly DependencyProperty CountPerPageProperty = DependencyProperty.Register("CountPerPage",
            typeof(int), _typeofSelf, new PropertyMetadata(50, OnCountPerPagePropertyChanged, CoerceCountPerPage));

        public int CountPerPage
        
            get => (int) GetValue(CountPerPageProperty);
            set => SetValue(CountPerPageProperty, value);
        

        private static object CoerceCountPerPage(DependencyObject d, object value)
        
            var countPerPage = (int) value;
            return Math.Max(countPerPage, 1);
        

        private static void OnCountPerPagePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        
            var ctrl = d as Pagination;
            var countPerPage = (int) e.NewValue;

            if (ctrl._countPerPageTextBox != null)
                ctrl._countPerPageTextBox.Text = countPerPage.ToString();

            ctrl.SetValue(PageCountPropertyKey, (int) Math.Ceiling(ctrl.Count * 1.0 / countPerPage));

            if (ctrl.Current != 1)
                ctrl.Current = 1;
            else
                ctrl.UpdatePages();
        

        public static readonly DependencyProperty CurrentProperty = DependencyProperty.Register("Current", typeof(int),
            _typeofSelf, new PropertyMetadata(1, OnCurrentPropertyChanged, CoerceCurrent));

        public int Current
        
            get => (int) GetValue(CurrentProperty);
            set => SetValue(CurrentProperty, value);
        

        private static object CoerceCurrent(DependencyObject d, object value)
        
            var current = (int) value;
            var ctrl = d as Pagination;

            return Math.Max(current, 1);
        

        private static void OnCurrentPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        
            var ctrl = d as Pagination;
            var current = (int) e.NewValue;

            if (ctrl._listBox != null)
                ctrl._listBox.SelectedItem = current.ToString();

            if (ctrl._jumpPageTextBox != null)
                ctrl._jumpPageTextBox.Text = current.ToString();

            ctrl.UpdatePages();
        

        #endregion

        #region Event

        /// <summary>
        ///     分页
        /// </summary>
        private void OnCountPerPageTextBoxChanged(object sender, TextChangedEventArgs e)
        
            if (int.TryParse(_countPerPageTextBox.Text, out var _ountPerPage))
                CountPerPage = _ountPerPage;
        

        /// <summary>
        ///     跳转页
        /// </summary>
        private void OnJumpPageTextBoxChanged(object sender, TextChangedEventArgs e)
        
            if (int.TryParse(_jumpPageTextBox.Text, out var _current))
                Current = _current;
        

        /// <summary>
        ///     选择页
        /// </summary>
        private void OnSelectionChanged(object sender, SelectionChangedEventArgs e)
        
            if (_listBox.SelectedItem == null)
                return;

            Current = int.Parse(_listBox.SelectedItem.ToString());
        

        #endregion

        #region Private

        private void Init()
        
            SetValue(PageCountPropertyKey, (int) Math.Ceiling(Count * 1.0 / CountPerPage));

            _jumpPageTextBox.Text = Current.ToString();
            //_jumpPageTextBox.Maximum = PageCount;

            _countPerPageTextBox.Text = CountPerPage.ToString();

            if (_listBox != null)
                _listBox.SelectedItem = Current.ToString();
        

        private void UnsubscribeEvents()
        
            if (_countPerPageTextBox != null)
                _countPerPageTextBox.TextChanged -= OnCountPerPageTextBoxChanged;

            if (_jumpPageTextBox != null)
                _jumpPageTextBox.TextChanged -= OnJumpPageTextBoxChanged;

            if (_listBox != null)
                _listBox.SelectionChanged -= OnSelectionChanged;
        

        private void SubscribeEvents()
        
            if (_countPerPageTextBox != null)
                _countPerPageTextBox.TextChanged += OnCountPerPageTextBoxChanged;

            if (_jumpPageTextBox != null)
                _jumpPageTextBox.TextChanged += OnJumpPageTextBoxChanged;

            if (_listBox != null)
                _listBox.SelectionChanged += OnSelectionChanged;
        

        private void UpdatePages()
        
            SetValue(PagesPropertyKey, GetPagers(Count, Current));

            if (_listBox != null && _listBox.SelectedItem == null)
                _listBox.SelectedItem = Current.ToString();
        

        private IEnumerable<string> GetPagers(int count, int current)
        
            if (count == 0)
                return null;

            if (PageCount <= 7)
                return Enumerable.Range(1, PageCount).Select(p => p.ToString()).ToArray();

            if (current <= 4)
                return new[] "1", "2", "3", "4", "5", Ellipsis, PageCount.ToString();

            if (current >= PageCount - 3)
                return new[]
                
                    "1", Ellipsis, (PageCount - 4).ToString(), (PageCount - 3).ToString(), (PageCount - 2).ToString(),
                    (PageCount - 1).ToString(), PageCount.ToString()
                ;

            return new[]
            
                "1", Ellipsis, (current - 1).ToString(), current.ToString(), (current + 1).ToString(), Ellipsis,
                PageCount.ToString()
            ;
        

        #endregion
    

2) Pagination.xaml 如下:

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    xmlns:input="clr-namespace:System.Windows.Input;assembly=PresentationCore"
                    xmlns:helpers="clr-namespace:WPFDevelopers.Helpers"
                    xmlns:controls="clr-namespace:WPFDevelopers.Controls">

    <ResourceDictionary.MergedDictionaries>
        <ResourceDictionary Source="Basic/ControlBasic.xaml"/>
    </ResourceDictionary.MergedDictionaries>

    <Style x:Key="PageListBoxStyleKey" TargetType="x:Type ListBox" 
           BasedOn="StaticResource ControlBasicStyle">
        <Setter Property="Background" Value="Transparent"/>
        <Setter Property="BorderThickness" Value="0"/>
        <Setter Property="Padding" Value="0"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="x:Type ListBox">
                    <Border BorderBrush="TemplateBinding BorderBrush" 
                            BorderThickness="TemplateBinding BorderThickness" 
                            Background="TemplateBinding Background" 
                            SnapsToDevicePixels="True">
                        <ScrollViewer Focusable="False" Padding="TemplateBinding Padding">
                            <ItemsPresenter SnapsToDevicePixels="TemplateBinding SnapsToDevicePixels"/>
                        </ScrollViewer>
                    </Border>
                    <ControlTemplate.Triggers>
                        <Trigger Property="IsGrouping" Value="True">
                            <Setter Property="ScrollViewer.CanContentScroll" Value="False"/>
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

    <Style x:Key="PageListBoxItemStyleKey" 
           TargetType="x:Type ListBoxItem"
           BasedOn="StaticResource ControlBasicStyle">
        <Setter Property="MinWidth" Value="32"/>
        <Setter Property="Cursor" Value="Hand"/>
        <Setter Property="HorizontalContentAlignment" Value="Center"/>
        <Setter Property="VerticalContentAlignment" Value="Center"/>
        <Setter Property="helpers:ElementHelper.CornerRadius" Value="3"/>
        <Setter Property="BorderThickness" Value="1"/>
        <Setter Property="Padding" Value="5,0"/>
        <Setter Property="Margin" Value="3,0"/>
        <Setter Property="Background" Value="DynamicResource BackgroundSolidColorBrush"/>
        <Setter Property="BorderBrush" Value="DynamicResource BaseSolidColorBrush"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="x:Type ListBoxItem">
                    <Border SnapsToDevicePixels="True"
                            Background="TemplateBinding Background" 
                            BorderThickness="TemplateBinding BorderThickness" 
                            BorderBrush="TemplateBinding BorderBrush"  
                            Padding="TemplateBinding Padding"
                            CornerRadius="Binding Path=(helpers:ElementHelper.CornerRadius),RelativeSource=RelativeSource TemplatedParent">
                        <ContentPresenter x:Name="PART_ContentPresenter" 
                                         HorizontalAlignment="TemplateBinding HorizontalContentAlignment" 
                                         VerticalAlignment="TemplateBinding VerticalContentAlignment"
                                         RecognizesAccessKey="True" 
                                         TextElement.Foreground="TemplateBinding Foreground"/>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
        <Style.Triggers>
            <DataTrigger Binding="Binding ." Value="···">
                <Setter Property="IsEnabled" Value="False"/>
                <Setter Property="FontWeight" Value="Bold"/>
            </DataTrigger>
            <Trigger Property="IsMouseOver" Value="True">
                <Setter Property="BorderBrush" Value="DynamicResource DefaultBorderBrushSolidColorBrush"/>
                <Setter Property="Background" Value="DynamicResource DefaultBackgroundSolidColorBrush"/>
                <Setter Property="Foreground" Value="DynamicResource PrimaryNormalSolidColorBrush"/>
            </Trigger>
            <Trigger Property="IsSelected" Value="True">
                <Setter Property="Background" Value="DynamicResource PrimaryPressedSolidColorBrush"/>
                <Setter Property="TextElement.Foreground" Value="DynamicResource WindowForegroundColorBrush"/>
            </Trigger>
        </Style.Triggers>
    </Style>

    <ControlTemplate x:Key="LitePagerControlTemplate" TargetType="x:Type controls:Pagination">
        <Border Background="TemplateBinding Background"
                BorderBrush="TemplateBinding BorderBrush"
                BorderThickness="TemplateBinding BorderThickness"
                Padding="TemplateBinding Padding">
            <Grid>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="Auto"/>
                    <ColumnDefinition Width="10"/>
                    <ColumnDefinition Width="Auto"/>
                    <ColumnDefinition Width="Auto"/>
                    <ColumnDefinition Width="10"/>
                    <ColumnDefinition Width="Auto"/>
                    <ColumnDefinition Width="5"/>
                    <ColumnDefinition Width="Auto"/>
                    <ColumnDefinition Width="5"/>
                    <ColumnDefinition Width="Auto"/>
                </Grid.ColumnDefinitions>
                <TextBlock VerticalAlignment="Center"
                           Text="Binding Count,StringFormat=共 0 条,RelativeSource=RelativeSource TemplatedParent"/>

               
                <TextBox Grid.Column="2" x:Name="PART_CountPerPageTextBox" 
                         TextAlignment="Center" VerticalContentAlignment="Center"
                         Width="60" MinWidth="0"
                         input:InputMethod.IsInputMethodEnabled="False"/>
                <TextBlock Grid.Column="3" Text=" 条 / 页" VerticalAlignment="Center"/>

                <Button Grid.Column="5" 
                        Command="x:Static controls:Pagination.PrevCommand">
                    <Path Width="7" Height="10" Stretch="Fill" 
                          Fill="Binding Foreground,RelativeSource=RelativeSource AncestorType=Button"
                          Data="StaticResource PathPrevious"/>
                </Button>

                
                <TextBox Grid.Column="7" x:Name="PART_JumpPageTextBox" 
                         TextAlignment="Center" 
                         VerticalContentAlignment="Center"
                         Width="60" MinWidth="0">
                    <TextBox.ToolTip>
                        <TextBlock>
                            <TextBlock.Text>
                                <MultiBinding StringFormat="0/1">
                                    <Binding Path="Current" RelativeSource="RelativeSource TemplatedParent"/>
                                    <Binding Path="PageCount" RelativeSource="RelativeSource TemplatedParent"/>
                                </MultiBinding>
                            </TextBlock.Text>
                        </TextBlock>
                    </TextBox.ToolTip>
                </TextBox>

                <Button Grid.Column="9" 
                        Command="x:Static controls:Pagination.NextCommand">
                    <Path Width="7" Height="10" Stretch="Fill" 
                          Fill="Binding Foreground,RelativeSource=RelativeSource AncestorType=Button"
                          Data="StaticResource PathNext"/>
                </Button>
            </Grid>
        </Border>
    </ControlTemplate>

    <Style TargetType="x:Type controls:Pagination" 
           BasedOn="StaticResource ControlBasicStyle">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="x:Type controls:Pagination">
                    <Border Background="TemplateBinding Background"
                            BorderBrush="TemplateBinding BorderBrush"
                            BorderThickness="TemplateBinding BorderThickness"
                            Padding="TemplateBinding Padding">
                        <Grid>
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="Auto"/>
                                <ColumnDefinition Width="Auto"/>
                                <ColumnDefinition Width="Auto"/>
                                <ColumnDefinition Width="*"/>
                                <ColumnDefinition Width="Auto"/>
                                <ColumnDefinition Width="Auto"/>
                            </Grid.ColumnDefinitions>
                            <TextBlock Margin="0,0,15,0" VerticalAlignment="Center"
                                       Text="Binding Count,StringFormat=共 0 条,RelativeSource=RelativeSource TemplatedParent"/>

                            <StackPanel Grid.Column="1" Orientation="Horizontal" Margin="0,0,15,0" >
                                <TextBlock Text="每页 " VerticalAlignment="Center"/>
                                <TextBox x:Name="PART_CountPerPageTextBox" 
                                         TextAlignment="Center" Width="60"
                                         MinWidth="0" VerticalContentAlignment="Center"
                                         FontSize="TemplateBinding FontSize" 
                                         input:InputMethod.IsInputMethodEnabled="False"/>
                                <TextBlock Text=" 条" VerticalAlignment="Center"/>
                            </StackPanel>

                            <Button Grid.Column="2" 
                                    Command="x:Static controls:Pagination.PrevCommand">
                                <Path Width="7" Height="10" Stretch="Fill" 
                                      Fill="Binding Foreground,RelativeSource=RelativeSource AncestorType=Button"
                                      Data="StaticResource PathPrevious"/>
                            </Button>

                            <ListBox x:Name="PART_ListBox" Grid.Column="3"
                                     SelectedIndex="0" Margin="5,0"
                                     ItemsSource="TemplateBinding Pages"
                                     Style="StaticResource PageListBoxStyleKey"
                                     ItemContainerStyle="StaticResource PageListBoxItemStyleKey"
                                     ScrollViewer.HorizontalScrollBarVisibility="Hidden"
                                     ScrollViewer.VerticalScrollBarVisibility="Hidden">
                                <ListBox.ItemsPanel>
                                    <ItemsPanelTemplate>
                                        <UniformGrid Rows="1"/>
                                    </ItemsPanelTemplate>
                                </ListBox.ItemsPanel>
                            </ListBox>

                            <Button Grid.Column="4" 
                                    Command="x:Static controls:Pagination.NextCommand">
                                <Path Width="7" Height="10" Stretch="Fill" 
                                      Fill="Binding Foreground,RelativeSource=RelativeSource AncestorType=Button"
                                      Data="StaticResource PathNext"/>
                            </Button>

                            <StackPanel Grid.Column="5" Orientation="Horizontal">
                                <TextBlock Text=" 前往 " VerticalAlignment="Center"/>
                               
                                <TextBox x:Name="PART_JumpPageTextBox"
                                         TextAlignment="Center" 
                                         ContextMenu="x:Null"
                                         Width="60" VerticalContentAlignment="Center"
                                         MinWidth="0"
                                         FontSize="TemplateBinding FontSize" />
                                <TextBlock Text=" 页" VerticalAlignment="Center"/>
                            </StackPanel>
                        </Grid>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
        <Style.Triggers>
            <Trigger Property="IsLite" Value="true">
                <Setter Property="Template" Value="StaticResource LitePagerControlTemplate"/>
            </Trigger>
        </Style.Triggers>
    </Style>

</ResourceDictionary>

3) 创建PaginationExampleVM.cs如下:

using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;

namespace WPFDevelopers.Samples.ViewModels

    public class PaginationExampleVM : ViewModelBase
    
        private List<int> _sourceList = new List<int>();

        public PaginationExampleVM()
        
            _sourceList.AddRange(Enumerable.Range(1, 300));
            Count = 300;

            CurrentPageChanged();
        

        public ObservableCollection<int> PaginationCollection  get; set;  = new ObservableCollection<int>();

        private int _count;
        public int Count
        
            get  return _count; 
            set  _count = value;  this.NotifyPropertyChange("Count"); CurrentPageChanged(); 
        

        private int _countPerPage = 10;
        public int CountPerPage
        
            get  return _countPerPage; 
            set  _countPerPage = value; this.NotifyPropertyChange("CountPerPage"); CurrentPageChanged(); 
        

        private int _current = 1;
        public int Current
        
            get  return _current; 
            set  _current = value; this.NotifyPropertyChange("Current"); CurrentPageChanged(); 
        

        private void CurrentPageChanged()
        
            PaginationCollection.Clear();

            foreach (var i in _sourceList.Skip((Current - 1) * CountPerPage).Take(CountPerPage))
            
                PaginationCollection.Add(i);
            
        
    

4) 使用 PaginationExample.xaml 如下:

<UserControl x:Class="WPFDevelopers.Samples.ExampleViews.PaginationExample"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:wpfdev="https://github.com/WPFDevelopersOrg/WPFDevelopers"
             xmlns:local="clr-namespace:WPFDevelopers.Samples.ExampleViews"
             mc:Ignorable="d" 
             d:DesignHeight="450" d:DesignWidth="800">
    <UserControl.Resources>
        <Style TargetType="x:Type TextBlock">
            <Setter Property="Foreground" Value="DynamicResource PrimaryTextSolidColorBrush" />
            <Setter Property="FontSize" Value="StaticResource NormalFontSize"/>
            <Setter Property="VerticalAlignment" Value="Center"/>
        </Style>
    </UserControl.Resources>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="50"/>
            <RowDefinition/>
            <RowDefinition Height="40"/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="2*"/>
            <ColumnDefinition Width="30"/>
            <ColumnDefinition Width="*"/>
        </Grid.ColumnDefinitions>
        <TextBlock Text="正常模式分页" HorizontalAlignment="Center" VerticalAlignment="Center"/>
        <TextBlock Grid.Column="2" Text="精简模式分页" HorizontalAlignment="Center" VerticalAlignment="Center"/>

        <ListBox Grid.Row="1" Grid.Column="0" ItemsSource="Binding NormalPaginationViewModel.PaginationCollection" Margin="20,0,0,0"/>
        <ListBox Grid.Row="1" Grid.Column="2" ItemsSource="Binding LitePaginationViewModel.PaginationCollection" Margin="0,0,20,0"/>

        <wpfdev:Pagination Grid.Row="2" Grid.Column="0" IsLite="False"  Margin="20,0,0,0"
                             Count="Binding NormalPaginationViewModel.Count,Mode=TwoWay"
                             CountPerPage="Binding NormalPaginationViewModel.CountPerPage,Mode=TwoWay"
                             Current="Binding NormalPaginationViewModel.Current,Mode=TwoWay"/>

        <wpfdev:Pagination Grid.Row="2" Grid.Column="2" IsLite="true"  Margin="0,0,20,0"
                             Count="Binding LitePaginationViewModel.Count,Mode=TwoWay"
                             CountPerPage="Binding LitePaginationViewModel.CountPerPage,Mode=TwoWay"
                             Current="Binding LitePaginationViewModel.Current,Mode=TwoWay"/>
    </Grid>
</UserControl>

5) 使用PaginationExample.xaml.cs如下:

using System.Windows.Controls;
using WPFDevelopers.Samples.ViewModels;

namespace WPFDevelopers.Samples.ExampleViews

    /// <summary>
    /// PaginationExample.xaml 的交互逻辑
    /// </summary>
    public partial class PaginationExample : UserControl
    
        public PaginationExampleVM NormalPaginationViewModel  get; set;  = new PaginationExampleVM();
        public PaginationExampleVM LitePaginationViewModel  get; set;  = new PaginationExampleVM();
        public PaginationExample()
        
            InitializeComponent();
            this.DataContext = this;
        
    

 鸣谢 - 黄佳

Github|Pagination[1]
码云|Pagination[2]

参考资料

[1]

Github|PaginationExample: https://github.com/WPFDevelopersOrg/WPFDevelopers/blob/master/src/WPFDevelopers.Samples/ExampleViews/PaginationExample.xaml

[2]

码云|PaginationExample: https://gitee.com/WPFDevelopersOrg/WPFDevelopers/blob/master/src/WPFDevelopers.Samples/ExampleViews/PaginationExample.xaml

以上是关于WPF 之列表分页控件的主要内容,如果未能解决你的问题,请参考以下文章

WPF 实现 DataGrid/ListView 分页控件(转)

WPF 实现 DataGrid/ListView 分页控件(转)

分页测试

WPF DataGrid如何分页、导出Excle、打印(急)

iOS控件之UIPageControl

WPF管理系统自定义分页控件 - WPF特工队内部资料