WPF 漂亮的自定义分页控件

 

# 所用到的关键知识点


① 自定义用户控件 (整个Page 是一个用自定义用户控件)
② 自定义控件    (每一个页面小按键是自定义控件)
③ 样式触发器  (Buttontype 改变时自动切换控件模板)
④ 自定义事件给引用者使用 (当点击每个页面按键时触发)
⑤ 依赖项属性 以及 属性改变回调事件
⑥ 其它

#开发和运行阶段的效果图片

1、开发时效果图

WPF 漂亮的自定义分页控件

2、运行时的效果图

WPF 漂亮的自定义分页控件
运行时效果

 

 

 

 

 

 

 

 

 

 

 

#  Paginater 的实现原码 

    public partial class Paginator : UserControl
    {
        #region variables
        private const String PageTag = "page";
        private const String FirstTag = "First";
        private const String UpTag = "Up";
        private const String NextTag = "Next";
        private const String LastTag = "Last";
        #endregion

        #region DependencyProperty Register

        public static readonly DependencyProperty SelectedForegroundProperty = DependencyProperty.Register("SelectedForground", typeof(Brush), typeof(TabButton), new PropertyMetadata(Brushes.Black, new PropertyChangedCallback(OnPropertyChanged)));
        public static readonly DependencyProperty SelectedeBackgroundProperty = DependencyProperty.Register("SelectedeBackground", typeof(Brush), typeof(TabButton), new PropertyMetadata(Brushes.LightSlateGray, new PropertyChangedCallback(OnPropertyChanged)));
        public static readonly DependencyProperty SelectedIndicatorColorProperty = DependencyProperty.Register("SelectedIndicatorColor", typeof(Brush), typeof(TabButton), new PropertyMetadata(Brushes.RoyalBlue, new PropertyChangedCallback(OnPropertyChanged)));
        public static readonly DependencyProperty SelectedIndicatorHeightProperty = DependencyProperty.Register("SelectedIndicatorHeight", typeof(int), typeof(TabButton), new PropertyMetadata(1, new PropertyChangedCallback(OnPropertyChanged)));
        public static readonly DependencyProperty ButtonTypeProperty = DependencyProperty.Register("ButtonType", typeof(PageButtonType), typeof(Paginator), new PropertyMetadata(PageButtonType.Radius, new PropertyChangedCallback(OnPropertyChanged)));
        public static readonly DependencyProperty DataCountProperty = DependencyProperty.Register("DataCount", typeof(int), typeof(Paginator), new FrameworkPropertyMetadata(0, new PropertyChangedCallback(OnDataCountChanged)));
        public static readonly DependencyProperty ItemCountCountProperty = DependencyProperty.Register("ItemCount", typeof(int), typeof(Paginator), new PropertyMetadata(10, new PropertyChangedCallback(OnPaginatorCountChanged)));
        public static readonly DependencyProperty CurrentPageProperty = DependencyProperty.Register("CurrentPage", typeof(int), typeof(Paginator), new PropertyMetadata(1, new PropertyChangedCallback(OnCurrentPageChanged)));
        #endregion

        /// <summary>
        ///  选中时的前景颜色
        /// </summary>
        public Brush SelectedForground
        {
            get { return (Brush)GetValue(SelectedForegroundProperty); }
            set { SetValue(SelectedForegroundProperty, value); }
        }


        public Brush SelectedBackground
        {
            get { return (Brush)GetValue(SelectedeBackgroundProperty); }
            set { SetValue(SelectedeBackgroundProperty, value); }
        }


        public Brush SelectedIndicatorColor
        {
            get { return (Brush)GetValue(SelectedIndicatorColorProperty); }
            set { SetValue(SelectedIndicatorColorProperty, value); }
        }

        public int SelectedIndicatorHeight
        {
            get { return (int)GetValue(SelectedIndicatorHeightProperty); }
            set { SetValue(SelectedIndicatorHeightProperty, value); }
        }


        public int DataCount
        {
            get { return (int)GetValue(DataCountProperty); }
            set { SetValue(DataCountProperty, value); }
        }

 

        public PageButtonType ButtonType
        {
            get { return (PageButtonType)GetValue(ButtonTypeProperty); }
            set { SetValue(ButtonTypeProperty, value); }
        }

        private static void OnDataCountChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            Paginator Paginator = sender as Paginator;
            Paginator.Measure();
        }

        private static void OnPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            Paginator p = sender as Paginator;
            p.Measure();
        }

        public int ItemCount
        {
            get { return (int)GetValue(ItemCountCountProperty); }
            set
            {
                if ((int)value <= 0)
                {
                    value = 10;
                }
                SetValue(ItemCountCountProperty, value);
            }
        }

        private static void OnPaginatorCountChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            Paginator Paginator = d as Paginator;
            Paginator.Measure();
        }

        public int CurrentPage
        {
            get { return (int)GetValue(CurrentPageProperty); }
            set { SetValue(CurrentPageProperty, value); }
        }
        public int LastPage { get; set; }


        #region  export event       

        public static readonly RoutedEvent PaginatorSelectedEvent = EventManager.RegisterRoutedEvent("PaginatorSelected", RoutingStrategy.Bubble, typeof(RoutedPropertyChangedEventHandler<int>), typeof(Paginator));

        public event RoutedPropertyChangedEventHandler<int> PaginatorSelected
        {
            add { AddHandler(PaginatorSelectedEvent, value); }
            remove { RemoveHandler(PaginatorSelectedEvent, value); }
        }

        private static void OnCurrentPageChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
        {
            Paginator Paginator = sender as Paginator;
            int oldValue = (int)args.OldValue;
            int newValue = (int)args.NewValue;
            Paginator.Measure();
            //引发事件
            Paginator.RaiseEventPaginatorSelected(newValue, oldValue);
        }
        private void RaiseEventPaginatorSelected(int newValue, int oldValue)
        {
            RoutedPropertyChangedEventArgs<int> args = new RoutedPropertyChangedEventArgs<int>(newValue, oldValue)
            {
                RoutedEvent = PaginatorSelectedEvent
            };
            RaiseEvent(args);
        }
        #endregion


        public Paginator()
        {
            InitializeComponent();
        }

        #region Measure

        private void Measure()
        {
            if (DataCount <= 0 || ItemCount <= 0)
            {
                return;
            }
            int pages = DataCount / ItemCount;
            if (DataCount % ItemCount > 0)
            {
                pages += 1;
            }
            LastPage = pages;
            //处理不需要动态生成的页面按键
            HandleStaticPageBtn();

            int side = 2;
            int windows = 6;

            if (pages > 1)
            {
                this.PagePanel.Visibility = Visibility.Visible;
                this.PagePanel.Children.Clear();
                if (pages < (side * windows))
                {
                    leftDot.Visibility = Visibility.Collapsed;
                    RightDot.Visibility = Visibility.Collapsed;
                    InsertPageBtn(1, pages);
                }
                else
                {
                    if (CurrentPage == 1)
                    {
                        RadiusUpPage.Visibility = Visibility.Collapsed;
                        CircleUpPage.Visibility = Visibility.Collapsed;
                        UdLineUpPage.Visibility = Visibility.Collapsed;
                    }
                    if (CurrentPage - windows <= 1) {
                        leftDot.Visibility = Visibility.Collapsed;
                        RadiusFirstPage.Visibility = Visibility.Collapsed;
                        CircleFirstPage.Visibility = Visibility.Collapsed;
                        UdLineFirstPage.Visibility = Visibility.Collapsed;
                    }

                    if (CurrentPage == pages)
                    {
                        RadiusNextPage.Visibility = Visibility.Collapsed;
                        CircleNextPage.Visibility = Visibility.Collapsed;
                        UdLineNextPage.Visibility = Visibility.Collapsed;                       
                    }
                    if ((CurrentPage + windows) < pages)
                    {
                        RadiusLastPage.Visibility = Visibility.Collapsed;
                        CircleLastPage.Visibility = Visibility.Collapsed;
                        UdLineLastPage.Visibility = Visibility.Collapsed;
                        RightDot.Visibility = Visibility.Collapsed;
                    }

                    if ((CurrentPage - windows) > 1)
                    {
                        leftDot.Visibility = Visibility.Visible;
                        switch (ButtonType)
                        {
                            case PageButtonType.Radius:
                                RadiusFirstPage.Visibility = Visibility.Visible;
                                break;
                            case PageButtonType.Circle:
                                CircleFirstPage.Visibility = Visibility.Visible;
                                break;
                            case PageButtonType.UdLine:
                                UdLineFirstPage.Visibility = Visibility.Visible;
                                break;
                        }                        
                    }
                    else
                    {
                        leftDot.Visibility = Visibility.Collapsed;
                        switch (ButtonType)
                        {
                            case PageButtonType.Radius:
                                RadiusFirstPage.Visibility = Visibility.Collapsed;
                                break;
                            case PageButtonType.Circle:
                                CircleFirstPage.Visibility = Visibility.Collapsed;
                                break;
                            case PageButtonType.UdLine:
                                UdLineFirstPage.Visibility = Visibility.Collapsed;
                                break;
                        }
                    }

                    if ((CurrentPage + windows) >= pages)
                    {
                        RightDot.Visibility = Visibility.Collapsed;
                        switch (ButtonType)
                        {
                            case PageButtonType.Radius:
                                RadiusLastPage.Visibility = Visibility.Collapsed;
                                break;
                            case PageButtonType.Circle:
                                CircleLastPage.Visibility = Visibility.Collapsed;
                                break;
                            case PageButtonType.UdLine:
                                UdLineLastPage.Visibility = Visibility.Collapsed;
                                break;
                        }
                    }
                    else
                    {
                        RightDot.Visibility = Visibility.Visible;
                        switch (ButtonType)
                        {
                            case PageButtonType.Radius:
                                RadiusLastPage.Visibility = Visibility.Visible;
                                break;
                            case PageButtonType.Circle:
                                CircleLastPage.Visibility = Visibility.Visible;
                                break;
                            case PageButtonType.UdLine:
                                UdLineLastPage.Visibility = Visibility.Visible;
                                break;
                        }                        
                    }
                    if (CurrentPage <= windows)
                    {
                        int end = CurrentPage + windows + (windows - CurrentPage);
                        InsertPageBtn(1, end);
                        if (end < pages)
                        {
                            RightDot.Visibility = Visibility.Visible;
                        }
                        else
                        {
                            RightDot.Visibility = Visibility.Collapsed;
                        }

                    }
                    else if (CurrentPage > windows)
                    {
                        int start = CurrentPage - windows;
                        if (start > 1)
                        {
                            leftDot.Visibility = Visibility.Visible;
                        }
                        else
                        {
                            leftDot.Visibility = Visibility.Collapsed;
                        }
                        int end = CurrentPage + windows;
                        if (end < pages)
                        {
                            RightDot.Visibility = Visibility.Visible;
                        }
                        else
                        {
                            end = end - (end - pages);
                            RightDot.Visibility = Visibility.Collapsed;
                        }
                        InsertPageBtn(start, end);
                    }
                }
            }
            else
            {
                this.PagePanel.Visibility = Visibility.Collapsed;
                leftDot.Visibility = Visibility.Collapsed;
                RightDot.Visibility = Visibility.Collapsed;
            }

        }


        private void InsertPageBtn(int startPage, int endPage)
        {
            for (int i = startPage; i <= endPage; i++)
            {
                if (i == CurrentPage)
                {
                    this.PagePanel.Children.Add(CreateBtn(i, true));
                }
                else
                {
                    this.PagePanel.Children.Add(CreateBtn(i));
                }
            }
        }
        #endregion

        /// <summary>
        /// 处理不需要动态生成的页面按键
        /// </summary>
        private void HandleStaticPageBtn()
        {
            if (LastPage <= 1)
            {
                RadiusFirstPage.Visibility = Visibility.Collapsed;
                RadiusUpPage.Visibility = Visibility.Collapsed;
                RadiusNextPage.Visibility = Visibility.Collapsed;
                RadiusLastPage.Visibility = Visibility.Collapsed;

                CircleFirstPage.Visibility = Visibility.Collapsed;
                CircleNextPage.Visibility = Visibility.Collapsed;
                CircleUpPage.Visibility = Visibility.Collapsed;
                CircleLastPage.Visibility = Visibility.Collapsed;

                UdLineFirstPage.Visibility = Visibility.Collapsed;
                UdLineUpPage.Visibility = Visibility.Collapsed;
                UdLineNextPage.Visibility = Visibility.Collapsed;
                UdLineLastPage.Visibility = Visibility.Collapsed;
                return;
            }
            switch (ButtonType)
            {
                case PageButtonType.UdLine:
                    RadiusFirstPage.Visibility = Visibility.Collapsed;
                    RadiusUpPage.Visibility = Visibility.Collapsed;
                    RadiusNextPage.Visibility = Visibility.Collapsed;
                    RadiusLastPage.Visibility = Visibility.Collapsed;

                    CircleFirstPage.Visibility = Visibility.Collapsed;
                    CircleNextPage.Visibility = Visibility.Collapsed;
                    CircleUpPage.Visibility = Visibility.Collapsed;
                    CircleLastPage.Visibility = Visibility.Collapsed;

                    UdLineFirstPage.Visibility = Visibility.Visible;
                    UdLineUpPage.Visibility = Visibility.Visible;
                    UdLineNextPage.Visibility = Visibility.Visible;
                    UdLineLastPage.Visibility = Visibility.Visible;
                    break;
                case PageButtonType.Circle:

                    RadiusFirstPage.Visibility = Visibility.Collapsed;
                    RadiusUpPage.Visibility = Visibility.Collapsed;
                    RadiusNextPage.Visibility = Visibility.Collapsed;
                    RadiusLastPage.Visibility = Visibility.Collapsed;

                    CircleFirstPage.Visibility = Visibility.Visible;
                    CircleNextPage.Visibility = Visibility.Visible;
                    CircleUpPage.Visibility = Visibility.Visible;
                    CircleLastPage.Visibility = Visibility.Visible;

                    UdLineFirstPage.Visibility = Visibility.Collapsed;
                    UdLineUpPage.Visibility = Visibility.Collapsed;
                    UdLineNextPage.Visibility = Visibility.Collapsed;
                    UdLineLastPage.Visibility = Visibility.Collapsed;
                    break;
                case PageButtonType.Radius:
                    RadiusFirstPage.Visibility = Visibility.Visible;
                    RadiusUpPage.Visibility = Visibility.Visible;
                    RadiusNextPage.Visibility = Visibility.Visible;
                    RadiusLastPage.Visibility = Visibility.Visible;

                    CircleFirstPage.Visibility = Visibility.Collapsed;
                    CircleNextPage.Visibility = Visibility.Collapsed;
                    CircleUpPage.Visibility = Visibility.Collapsed;
                    CircleLastPage.Visibility = Visibility.Collapsed;

                    UdLineFirstPage.Visibility = Visibility.Collapsed;
                    UdLineUpPage.Visibility = Visibility.Collapsed;
                    UdLineNextPage.Visibility = Visibility.Collapsed;
                    UdLineLastPage.Visibility = Visibility.Collapsed;
                    break;
                default:
                    RadiusFirstPage.Visibility = Visibility.Visible;
                    RadiusUpPage.Visibility = Visibility.Visible;
                    RadiusNextPage.Visibility = Visibility.Visible;
                    RadiusLastPage.Visibility = Visibility.Visible;

                    CircleFirstPage.Visibility = Visibility.Collapsed;
                    CircleNextPage.Visibility = Visibility.Collapsed;
                    CircleUpPage.Visibility = Visibility.Collapsed;
                    CircleLastPage.Visibility = Visibility.Collapsed;

                    UdLineFirstPage.Visibility = Visibility.Collapsed;
                    UdLineUpPage.Visibility = Visibility.Collapsed;
                    UdLineNextPage.Visibility = Visibility.Collapsed;
                    UdLineLastPage.Visibility = Visibility.Collapsed;
                    break;
            }

        }

        private PageButton CreateBtn(int PaginatorIndex, Boolean isCurrent = false)
        {
            PageButton button = new PageButton();
            button.Content = PaginatorIndex.ToString();
            button.Type = (int)ButtonType;
            button.FontSize = this.FontSize;
            button.IsChecked = isCurrent;
            button.IndicatorHeight = SelectedIndicatorHeight;
            button.Tag = PageTag;
            button.ActiveForground = SelectedForground;
            button.ActiveIndicatorColor = this.SelectedIndicatorColor;
            button.ActiveBackground = this.SelectedBackground;
            button.Background = this.Background;
            button.Click += PageButton_Click;
            return button;
        }

        private void PageButton_Click(object sender, RoutedEventArgs e)
        {
            PageButton button = sender as PageButton;
            String tag = button.Tag.ToString();
            int index = 0;
            try
            {
                index = Convert.ToInt32(button.Content);
                CurrentPage = index;
            }
            catch
            {
                // static orther btn
                button.IsChecked = false;
                switch (tag)
                {
                    case FirstTag:
                        CurrentPage = 1;
                        break;
                    case UpTag:
                        CurrentPage -= 1;
                        break;
                    case NextTag:
                        CurrentPage += 1;
                        break;
                    case LastTag:
                        CurrentPage = LastPage;
                        break;
                    default:
                        break;
                }
            }
            Console.WriteLine("==== :" + tag + " page:" + index);
        }

        private void UserControl_Loaded(object sender, RoutedEventArgs e)
        {
            Measure();
        }
    }

 

#、XAML

<UserControl x:Class="MyCustomControlLibrary.Paginator"
             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:local="clr-namespace:MyCustomControlLibrary"
             mc:Ignorable="d" Background="White"
             Loaded="UserControl_Loaded"
             d:DesignHeight="450" d:DesignWidth="800">
    <Grid>
       
            <StackPanel Orientation="Horizontal" x:Name="PageContine" VerticalAlignment="Center">                
            <local:PageButton x:Name="RadiusFirstPage" Tag="First" Width="50" Content="首页" Type="2" Margin="2" ActiveBackground="{StaticResource myBlue}" ActiveForground="White" Padding="1" Click="PageButton_Click"/>
            <local:PageButton x:Name="CircleFirstPage" Tag="First" Content="首" Type="1" Margin="2" ActiveBackground="{StaticResource myBlue}" ActiveForground="White" Padding="1"  Click="PageButton_Click"/>
            <local:PageButton x:Name="UdLineFirstPage" Tag="First" Content="首" Type="0" Margin="2" ActiveBackground="{StaticResource myBlue}" ActiveForground="{StaticResource myBlue}" Padding="1"  Click="PageButton_Click"/>

            <local:PageButton x:Name="RadiusUpPage" Tag="Up" Width="50" Content="上一页" Type="2" Margin="2" ActiveBackground="{StaticResource myBlue}" ActiveForground="White" Padding="1"  Click="PageButton_Click"/>
            <local:PageButton x:Name="CircleUpPage" Tag="Up" Content="上" Type="1" Margin="2" ActiveBackground="{StaticResource myBlue}" ActiveForground="White" Padding="1"  Click="PageButton_Click"/>
            <local:PageButton x:Name="UdLineUpPage" Tag="Up" Content="上" Type="0" Margin="2" ActiveBackground="{StaticResource myBlue}" ActiveForground="{StaticResource myBlue}" Padding="1"  Click="PageButton_Click"/>


                <TextBlock x:Name="leftDot" Text="……" FontSize="14" VerticalAlignment="Bottom" Margin="2" Visibility="Collapsed"/>
                <WrapPanel x:Name="PagePanel" Visibility="Visible">
                <local:PageButton  Content="1"  Type="2" Margin="2"  ActiveBackground="{StaticResource myBlue}" ActiveForground="White" Padding="1" IsChecked="True"  Click="PageButton_Click"/>
                <local:PageButton  Content="2"  Type="2" Margin="2"  ActiveBackground="{StaticResource myBlue}" ActiveForground="White" Padding="1"  Click="PageButton_Click"/>
                <local:PageButton  Content="3"  Type="2" Margin="2"  ActiveBackground="{StaticResource myBlue}" ActiveForground="White" Padding="1"  Click="PageButton_Click"/>
                <local:PageButton  Content="4"  Type="2" Margin="2"  ActiveBackground="{StaticResource myBlue}" ActiveForground="White" Padding="1"  Click="PageButton_Click"/>
                <local:PageButton  Content="5"  Type="2" Margin="2"  ActiveBackground="{StaticResource myBlue}" ActiveForground="White" Padding="1"  Click="PageButton_Click"/>
                <local:PageButton  Content="6"  Type="2" Margin="2"  ActiveBackground="{StaticResource myBlue}" ActiveForground="White" Padding="1"  Click="PageButton_Click"/>
                <local:PageButton  Content="7"  Type="2" Margin="2"  ActiveBackground="{StaticResource myBlue}" ActiveForground="White" Padding="1"  Click="PageButton_Click"/>
                </WrapPanel>
            <TextBlock x:Name="RightDot" Text="……" FontSize="14" VerticalAlignment="Bottom" Margin="2" Visibility="Collapsed"/>

            <local:PageButton x:Name="RadiusNextPage" Tag="Next" Content="下一页" Width="50"  Type="2" Margin="2"  ActiveBackground="{StaticResource myBlue}" ActiveForground="White" Padding="1"  Click="PageButton_Click"/>
            <local:PageButton x:Name="CircleNextPage" Tag="Next" Content="下" Type="1" Margin="2"  ActiveBackground="{StaticResource myBlue}" ActiveForground="White" Padding="1"  Click="PageButton_Click"/>
            <local:PageButton x:Name="UdLineNextPage" Tag="Next" Content="下" Type="0" Margin="2" ActiveIndicatorColor="{StaticResource myBlue}" ActiveBackground="{StaticResource myBlue}" ActiveForground="{StaticResource myBlue}" Padding="1"  Click="PageButton_Click"/>

            <local:PageButton x:Name="RadiusLastPage" Tag="Last" Width="50" Content="尾页" Type="2" Margin="2"  ActiveBackground="{StaticResource myBlue}" ActiveForground="White" Padding="1"  Click="PageButton_Click"/>
            <local:PageButton x:Name="CircleLastPage" Tag="Last"  Content="尾" Type="2" Margin="1"  ActiveBackground="{StaticResource myBlue}" ActiveForground="White" Padding="1"  Click="PageButton_Click"/>
            <local:PageButton x:Name="UdLineLastPage" Tag="Last" Content="尾" Type="0" Margin="2"  ActiveBackground="{StaticResource myBlue}" ActiveForground="{StaticResource myBlue}" Padding="1"  Click="PageButton_Click"/>
            </StackPanel>

    </Grid>
</UserControl>


5、 后端代码有点乱 ,是因为XAML 默认就显示些控件 如上一面 首页 这些不需要动态生成的,主要为了性能的考虑 。

      如果这些控件也动态生成,可能后端代码会少很多。

好久没有好好的搞代码拉,花了整整两天的时间。不足之处欢迎指出,也希望能帮到一些朋面。