using System; using System.Windows; using System.Windows.Controls; using System.Windows.Input; using HandyControl.Data; using HandyControl.Interactivity; using HandyControl.Tools; using HandyControl.Tools.Extension; namespace HandyControl.Controls; /// /// 页码 /// [TemplatePart(Name = ElementButtonLeft, Type = typeof(Button))] [TemplatePart(Name = ElementButtonRight, Type = typeof(Button))] [TemplatePart(Name = ElementButtonFirst, Type = typeof(RadioButton))] [TemplatePart(Name = ElementMoreLeft, Type = typeof(FrameworkElement))] [TemplatePart(Name = ElementPanelMain, Type = typeof(Panel))] [TemplatePart(Name = ElementMoreRight, Type = typeof(FrameworkElement))] [TemplatePart(Name = ElementButtonLast, Type = typeof(RadioButton))] [TemplatePart(Name = ElementButtonLast, Type = typeof(NumericUpDown))] public class Pagination : Control { #region Constants private const string ElementButtonLeft = "PART_ButtonLeft"; private const string ElementButtonRight = "PART_ButtonRight"; private const string ElementButtonFirst = "PART_ButtonFirst"; private const string ElementMoreLeft = "PART_MoreLeft"; private const string ElementPanelMain = "PART_PanelMain"; private const string ElementMoreRight = "PART_MoreRight"; private const string ElementButtonLast = "PART_ButtonLast"; private const string ElementJump = "PART_Jump"; #endregion Constants #region Data private Button _buttonLeft; private Button _buttonRight; private RadioButton _buttonFirst; private FrameworkElement _moreLeft; private Panel _panelMain; private FrameworkElement _moreRight; private RadioButton _buttonLast; private NumericUpDown _jumpNumericUpDown; private bool _appliedTemplate; #endregion Data #region Public Events /// /// 页面更新事件 /// public static readonly RoutedEvent PageUpdatedEvent = EventManager.RegisterRoutedEvent("PageUpdated", RoutingStrategy.Bubble, typeof(EventHandler>), typeof(Pagination)); /// /// 页面更新事件 /// public event EventHandler> PageUpdated { add => AddHandler(PageUpdatedEvent, value); remove => RemoveHandler(PageUpdatedEvent, value); } #endregion Public Events public Pagination() { CommandBindings.Add(new CommandBinding(ControlCommands.Prev, ButtonPrev_OnClick)); CommandBindings.Add(new CommandBinding(ControlCommands.Next, ButtonNext_OnClick)); CommandBindings.Add(new CommandBinding(ControlCommands.Selected, ToggleButton_OnChecked)); CommandBindings.Add(new CommandBinding(ControlCommands.Jump, (s, e) => PageIndex = (int) _jumpNumericUpDown.Value)); OnAutoHidingChanged(AutoHiding); Update(); } #region Public Properties #region MaxPageCount /// /// 最大页数 /// public static readonly DependencyProperty MaxPageCountProperty = DependencyProperty.Register( nameof(MaxPageCount), typeof(int), typeof(Pagination), new PropertyMetadata(ValueBoxes.Int1Box, OnMaxPageCountChanged, CoerceMaxPageCount), ValidateHelper.IsInRangeOfPosIntIncludeZero); private static object CoerceMaxPageCount(DependencyObject d, object basevalue) { var intValue = (int) basevalue; return intValue < 1 ? 1 : intValue; } private static void OnMaxPageCountChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { if (d is Pagination pagination) { if (pagination.PageIndex > pagination.MaxPageCount) { pagination.PageIndex = pagination.MaxPageCount; } pagination.CoerceValue(PageIndexProperty); pagination.OnAutoHidingChanged(pagination.AutoHiding); pagination.Update(); } } /// /// 最大页数 /// public int MaxPageCount { get => (int) GetValue(MaxPageCountProperty); set => SetValue(MaxPageCountProperty, value); } #endregion MaxPageCount #region DataCountPerPage /// /// 每页的数据量 /// public static readonly DependencyProperty DataCountPerPageProperty = DependencyProperty.Register( nameof(DataCountPerPage), typeof(int), typeof(Pagination), new PropertyMetadata(20, OnDataCountPerPageChanged), ValidateHelper.IsInRangeOfPosInt); private static void OnDataCountPerPageChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { if (d is Pagination pagination) { pagination.Update(); } } /// /// 每页的数据量 /// public int DataCountPerPage { get => (int) GetValue(DataCountPerPageProperty); set => SetValue(DataCountPerPageProperty, value); } #endregion #region PageIndex /// /// 当前页 /// public static readonly DependencyProperty PageIndexProperty = DependencyProperty.Register( nameof(PageIndex), typeof(int), typeof(Pagination), new PropertyMetadata(ValueBoxes.Int1Box, OnPageIndexChanged, CoercePageIndex), ValidateHelper.IsInRangeOfPosIntIncludeZero); private static object CoercePageIndex(DependencyObject d, object basevalue) { if (d is not Pagination pagination) return 1; var intValue = (int) basevalue; return intValue < 1 ? 1 : intValue > pagination.MaxPageCount ? pagination.MaxPageCount : intValue; } private static void OnPageIndexChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { if (d is Pagination pagination && e.NewValue is int value) { pagination.Update(); pagination.RaiseEvent(new FunctionEventArgs(PageUpdatedEvent, pagination) { Info = value }); } } /// /// 当前页 /// public int PageIndex { get => (int) GetValue(PageIndexProperty); set => SetValue(PageIndexProperty, value); } #endregion PageIndex #region MaxPageInterval /// /// 表示当前选中的按钮距离左右两个方向按钮的最大间隔(4表示间隔4个按钮,如果超过则用省略号表示) /// public static readonly DependencyProperty MaxPageIntervalProperty = DependencyProperty.Register( nameof(MaxPageInterval), typeof(int), typeof(Pagination), new PropertyMetadata(3, OnMaxPageIntervalChanged), ValidateHelper.IsInRangeOfPosIntIncludeZero); private static void OnMaxPageIntervalChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { if (d is Pagination pagination) { pagination.Update(); } } /// /// 表示当前选中的按钮距离左右两个方向按钮的最大间隔(4表示间隔4个按钮,如果超过则用省略号表示) /// public int MaxPageInterval { get => (int) GetValue(MaxPageIntervalProperty); set => SetValue(MaxPageIntervalProperty, value); } #endregion MaxPageInterval #region IsJumpEnabled public static readonly DependencyProperty IsJumpEnabledProperty = DependencyProperty.Register( nameof(IsJumpEnabled), typeof(bool), typeof(Pagination), new PropertyMetadata(ValueBoxes.FalseBox)); public bool IsJumpEnabled { get => (bool) GetValue(IsJumpEnabledProperty); set => SetValue(IsJumpEnabledProperty, ValueBoxes.BooleanBox(value)); } #endregion #region AutoHiding public static readonly DependencyProperty AutoHidingProperty = DependencyProperty.Register( nameof(AutoHiding), typeof(bool), typeof(Pagination), new PropertyMetadata(ValueBoxes.TrueBox, OnAutoHidingChanged)); private static void OnAutoHidingChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { if (d is Pagination pagination) { pagination.OnAutoHidingChanged((bool) e.NewValue); } } private void OnAutoHidingChanged(bool newValue) => this.Show(!newValue || MaxPageCount > 1); public bool AutoHiding { get => (bool) GetValue(AutoHidingProperty); set => SetValue(AutoHidingProperty, ValueBoxes.BooleanBox(value)); } #endregion public static readonly DependencyProperty PaginationButtonStyleProperty = DependencyProperty.Register( nameof(PaginationButtonStyle), typeof(Style), typeof(Pagination), new PropertyMetadata(default(Style))); public Style PaginationButtonStyle { get => (Style) GetValue(PaginationButtonStyleProperty); set => SetValue(PaginationButtonStyleProperty, value); } #endregion #region Public Methods public override void OnApplyTemplate() { _appliedTemplate = false; base.OnApplyTemplate(); _buttonLeft = GetTemplateChild(ElementButtonLeft) as Button; _buttonRight = GetTemplateChild(ElementButtonRight) as Button; _buttonFirst = GetTemplateChild(ElementButtonFirst) as RadioButton; _moreLeft = GetTemplateChild(ElementMoreLeft) as FrameworkElement; _panelMain = GetTemplateChild(ElementPanelMain) as Panel; _moreRight = GetTemplateChild(ElementMoreRight) as FrameworkElement; _buttonLast = GetTemplateChild(ElementButtonLast) as RadioButton; _jumpNumericUpDown = GetTemplateChild(ElementJump) as NumericUpDown; CheckNull(); _appliedTemplate = true; Update(); } #endregion Public Methods #region Private Methods private void CheckNull() { if (_buttonLeft == null || _buttonRight == null || _buttonFirst == null || _moreLeft == null || _panelMain == null || _moreRight == null || _buttonLast == null) throw new Exception(); } /// /// 更新 /// private void Update() { if (!_appliedTemplate) return; _buttonLeft.IsEnabled = PageIndex > 1; _buttonRight.IsEnabled = PageIndex < MaxPageCount; if (MaxPageInterval == 0) { _buttonFirst.Collapse(); _buttonLast.Collapse(); _moreLeft.Collapse(); _moreRight.Collapse(); _panelMain.Children.Clear(); var selectButton = CreateButton(PageIndex); _panelMain.Children.Add(selectButton); selectButton.IsChecked = true; return; } _buttonFirst.Show(); _buttonLast.Show(); _moreLeft.Show(); _moreRight.Show(); //更新最后一页 if (MaxPageCount == 1) { _buttonLast.Collapse(); } else { _buttonLast.Show(); _buttonLast.Content = MaxPageCount.ToString(); } //更新省略号 var right = MaxPageCount - PageIndex; var left = PageIndex - 1; _moreRight.Show(right > MaxPageInterval); _moreLeft.Show(left > MaxPageInterval); //更新中间部分 _panelMain.Children.Clear(); if (PageIndex > 1 && PageIndex < MaxPageCount) { var selectButton = CreateButton(PageIndex); _panelMain.Children.Add(selectButton); selectButton.IsChecked = true; } else if (PageIndex == 1) { _buttonFirst.IsChecked = true; } else { _buttonLast.IsChecked = true; } var sub = PageIndex; for (var i = 0; i < MaxPageInterval - 1; i++) { if (--sub > 1) { _panelMain.Children.Insert(0, CreateButton(sub)); } else { break; } } var add = PageIndex; for (var i = 0; i < MaxPageInterval - 1; i++) { if (++add < MaxPageCount) { _panelMain.Children.Add(CreateButton(add)); } else { break; } } } private void ButtonPrev_OnClick(object sender, RoutedEventArgs e) => PageIndex--; private void ButtonNext_OnClick(object sender, RoutedEventArgs e) => PageIndex++; private RadioButton CreateButton(int page) { return new() { Style = PaginationButtonStyle, Content = page.ToString() }; } private void ToggleButton_OnChecked(object sender, RoutedEventArgs e) { if (e.OriginalSource is not RadioButton button) return; if (button.IsChecked == false) return; PageIndex = int.Parse(button.Content.ToString()); } #endregion Private Methods }