using Muchinfo.DataPager.Base; using Muchinfo.DataPager.Extensions; using System; using System.ComponentModel; using System.Windows; using System.Windows.Controls; using System.Windows.Input; namespace Muchinfo.DataPager { public class MuchinfoPager : Control, ICommandSource { #region Fields private bool? _initializingData = null; private bool _areHandlersSuspended; public static readonly DependencyProperty PageIndexProperty; public static readonly DependencyProperty PageSizeProperty; public static readonly DependencyProperty ItemCountProperty; private static readonly DependencyPropertyKey PageCountPropertyKey; public static readonly DependencyProperty PageCountProperty; private static readonly DependencyPropertyKey CanMoveToFirstPagePropertyKey; public static readonly DependencyProperty CanMoveToFirstPageProperty; private static readonly DependencyPropertyKey CanMoveToLastPagePropertyKey; public static readonly DependencyProperty CanMoveToLastPageProperty; private static readonly DependencyPropertyKey CanMoveToNextPagePropertyKey; public static readonly DependencyProperty CanMoveToNextPageProperty; private static readonly DependencyPropertyKey CanChangePagePropertyKey; public static readonly DependencyProperty CanChangePageProperty; private static readonly DependencyPropertyKey CanMoveToPreviousPagePropertyKey; public static readonly DependencyProperty CanMoveToPreviousPageProperty; public static readonly DependencyProperty NumericButtonCountProperty; public static readonly DependencyProperty NumericButtonStyleProperty; #endregion #region Properties public int PageIndex { get { return (int)base.GetValue(MuchinfoPager.PageIndexProperty); } set { base.SetValue(MuchinfoPager.PageIndexProperty, value); } } public int PageSize { get { return (int)base.GetValue(MuchinfoPager.PageSizeProperty); } set { base.SetValue(MuchinfoPager.PageSizeProperty, value); } } public int ItemCount { get { return (int)base.GetValue(MuchinfoPager.ItemCountProperty); } set { base.SetValue(MuchinfoPager.ItemCountProperty, value); } } public int PageCount { get { return (int)base.GetValue(MuchinfoPager.PageCountProperty); } private set { base.SetValue(MuchinfoPager.PageCountPropertyKey, value); } } public bool CanMoveToFirstPage { get { return (bool)base.GetValue(MuchinfoPager.CanMoveToFirstPageProperty); } private set { base.SetValue(MuchinfoPager.CanMoveToFirstPagePropertyKey, value); } } public bool CanMoveToLastPage { get { return (bool)base.GetValue(MuchinfoPager.CanMoveToLastPageProperty); } private set { base.SetValue(MuchinfoPager.CanMoveToLastPagePropertyKey, value); } } public bool CanMoveToNextPage { get { return (bool)base.GetValue(MuchinfoPager.CanMoveToNextPageProperty); } private set { base.SetValue(MuchinfoPager.CanMoveToNextPagePropertyKey, value); } } public bool CanChangePage { get { return (bool)base.GetValue(MuchinfoPager.CanChangePageProperty); } private set { base.SetValue(MuchinfoPager.CanChangePagePropertyKey, value); } } public bool CanMoveToPreviousPage { get { return (bool)base.GetValue(MuchinfoPager.CanMoveToPreviousPageProperty); } private set { base.SetValue(MuchinfoPager.CanMoveToPreviousPagePropertyKey, value); } } public int NumericButtonCount { get { return (int)base.GetValue(MuchinfoPager.NumericButtonCountProperty); } set { base.SetValue(MuchinfoPager.NumericButtonCountProperty, value); } } public Style NumericButtonStyle { get { return (Style)base.GetValue(MuchinfoPager.NumericButtonStyleProperty); } set { base.SetValue(MuchinfoPager.NumericButtonStyleProperty, value); } } private bool IsInitializingData { get { return this._initializingData.HasValue && this._initializingData.Value; } } #endregion #region Command Handle private static void RegisterCommand(ICommand command, ExecutedRoutedEventHandler executed, CanExecuteRoutedEventHandler canExecute) { CommandManager.RegisterClassCommandBinding(typeof(MuchinfoPager), new CommandBinding(command, executed, canExecute)); } private static void RegisterCommands() { MuchinfoPager.RegisterCommand(MuchinfoPagerCommands.MoveToFirstPage, new ExecutedRoutedEventHandler(MuchinfoPager.OnMoveToFirstPage), new CanExecuteRoutedEventHandler(MuchinfoPager.CanMoveToFirstPageExecute)); MuchinfoPager.RegisterCommand(MuchinfoPagerCommands.MoveToLastPage, new ExecutedRoutedEventHandler(MuchinfoPager.OnMoveToLastPage), new CanExecuteRoutedEventHandler(MuchinfoPager.CanMoveToLastPageExecute)); MuchinfoPager.RegisterCommand(MuchinfoPagerCommands.MoveToNextPage, new ExecutedRoutedEventHandler(MuchinfoPager.OnMoveToNextPage), new CanExecuteRoutedEventHandler(MuchinfoPager.CanMoveToNextPageExecute)); MuchinfoPager.RegisterCommand(MuchinfoPagerCommands.MoveToPage, new ExecutedRoutedEventHandler(MuchinfoPager.OnMoveToPage), new CanExecuteRoutedEventHandler(MuchinfoPager.CanMoveToPageExecute)); MuchinfoPager.RegisterCommand(MuchinfoPagerCommands.MoveToPreviousPage, new ExecutedRoutedEventHandler(MuchinfoPager.OnMoveToPreviousPage), new CanExecuteRoutedEventHandler(MuchinfoPager.CanMoveToPreviousPageExecute)); } private static void OnMoveToFirstPage(object sender, ExecutedRoutedEventArgs e) { MuchinfoPager MuchinfoDataPager = sender as MuchinfoPager; if (MuchinfoDataPager != null) { MuchinfoDataPager.MoveToFirstPage(); } } private static void CanMoveToFirstPageExecute(object sender, CanExecuteRoutedEventArgs e) { MuchinfoPager MuchinfoDataPager = sender as MuchinfoPager; if (MuchinfoDataPager != null) { e.CanExecute = MuchinfoDataPager.CanMoveToFirstPage; } } private static void OnMoveToLastPage(object sender, ExecutedRoutedEventArgs e) { MuchinfoPager MuchinfoDataPager = sender as MuchinfoPager; if (MuchinfoDataPager != null) { MuchinfoDataPager.MoveToLastPage(); } } private static void CanMoveToLastPageExecute(object sender, CanExecuteRoutedEventArgs e) { e.CanExecute = false; MuchinfoPager MuchinfoDataPager = sender as MuchinfoPager; if (MuchinfoDataPager != null) { e.CanExecute = MuchinfoDataPager.CanMoveToLastPage; } } private static void OnMoveToNextPage(object sender, ExecutedRoutedEventArgs e) { MuchinfoPager MuchinfoDataPager = sender as MuchinfoPager; if (MuchinfoDataPager != null) { MuchinfoDataPager.MoveToNextPage(); } } private static void CanMoveToNextPageExecute(object sender, CanExecuteRoutedEventArgs e) { e.CanExecute = false; MuchinfoPager MuchinfoDataPager = sender as MuchinfoPager; if (MuchinfoDataPager != null) { e.CanExecute = MuchinfoDataPager.CanMoveToNextPage; } } private static void OnMoveToPage(object sender, ExecutedRoutedEventArgs e) { MuchinfoPager MuchinfoDataPager = sender as MuchinfoPager; if (MuchinfoDataPager != null) { if (!(e.Parameter is int)) { throw new ArgumentException("The parameter of the MoveToPage command should be an integer."); } MuchinfoDataPager.MoveToPage((int)e.Parameter); } } private static void CanMoveToPageExecute(object sender, CanExecuteRoutedEventArgs e) { e.CanExecute = false; MuchinfoPager MuchinfoDataPager = sender as MuchinfoPager; if (MuchinfoDataPager != null) { e.CanExecute = MuchinfoDataPager.CanChangePage; } } private static void OnMoveToPreviousPage(object sender, ExecutedRoutedEventArgs e) { MuchinfoPager MuchinfoDataPager = sender as MuchinfoPager; if (MuchinfoDataPager != null) { MuchinfoDataPager.MoveToPreviousPage(); } } private static void CanMoveToPreviousPageExecute(object sender, CanExecuteRoutedEventArgs e) { e.CanExecute = false; MuchinfoPager MuchinfoDataPager = sender as MuchinfoPager; if (MuchinfoDataPager != null) { e.CanExecute = MuchinfoDataPager.CanMoveToPreviousPage; } } #endregion #region Constructor static MuchinfoPager() { MuchinfoPager.PageIndexProperty = DependencyPropertyExtensions.Register("PageIndex", typeof(int), typeof(MuchinfoPager), new PropertyMetadata(-1, new PropertyChangedCallback(MuchinfoPager.OnPageIndexPropertyChanged)), new ValidateValueCallback(MuchinfoPager.IsValidDataPagerIndex)); MuchinfoPager.PageSizeProperty = DependencyProperty.Register("PageSize", typeof(int), typeof(MuchinfoPager), new PropertyMetadata(20, new PropertyChangedCallback(MuchinfoPager.OnPageSizePropertyChanged))); MuchinfoPager.ItemCountProperty = DependencyProperty.Register("ItemCount", typeof(int), typeof(MuchinfoPager), new PropertyMetadata(new PropertyChangedCallback(MuchinfoPager.OnItemCountPropertyChanged))); MuchinfoPager.PageCountPropertyKey = DependencyPropertyExtensions.RegisterReadOnly("PageCount", typeof(int), typeof(MuchinfoPager), new PropertyMetadata()); MuchinfoPager.PageCountProperty = MuchinfoPager.PageCountPropertyKey.DependencyProperty; MuchinfoPager.CanMoveToFirstPagePropertyKey = DependencyPropertyExtensions.RegisterReadOnly("CanMoveToFirstPage", typeof(bool), typeof(MuchinfoPager), new PropertyMetadata()); MuchinfoPager.CanMoveToFirstPageProperty = MuchinfoPager.CanMoveToFirstPagePropertyKey.DependencyProperty; MuchinfoPager.CanMoveToLastPagePropertyKey = DependencyPropertyExtensions.RegisterReadOnly("CanMoveToLastPage", typeof(bool), typeof(MuchinfoPager), new PropertyMetadata()); MuchinfoPager.CanMoveToLastPageProperty = MuchinfoPager.CanMoveToLastPagePropertyKey.DependencyProperty; MuchinfoPager.CanMoveToNextPagePropertyKey = DependencyPropertyExtensions.RegisterReadOnly("CanMoveToNextPage", typeof(bool), typeof(MuchinfoPager), new PropertyMetadata()); MuchinfoPager.CanMoveToNextPageProperty = MuchinfoPager.CanMoveToNextPagePropertyKey.DependencyProperty; MuchinfoPager.CanChangePagePropertyKey = DependencyPropertyExtensions.RegisterReadOnly("CanChangePage", typeof(bool), typeof(MuchinfoPager), new PropertyMetadata()); MuchinfoPager.CanChangePageProperty = MuchinfoPager.CanChangePagePropertyKey.DependencyProperty; MuchinfoPager.CanMoveToPreviousPagePropertyKey = DependencyPropertyExtensions.RegisterReadOnly("CanMoveToPreviousPage", typeof(bool), typeof(MuchinfoPager), new PropertyMetadata()); MuchinfoPager.CanMoveToPreviousPageProperty = MuchinfoPager.CanMoveToPreviousPagePropertyKey.DependencyProperty; MuchinfoPager.NumericButtonCountProperty = DependencyProperty.Register("NumericButtonCount", typeof(int), typeof(MuchinfoPager), new PropertyMetadata(10)); MuchinfoPager.NumericButtonStyleProperty = DependencyProperty.Register("NumericButtonStyle", typeof(Style), typeof(MuchinfoPager), new PropertyMetadata(null)); MuchinfoPager.RegisterCommands(); FrameworkElement.DefaultStyleKeyProperty.OverrideMetadata(typeof(MuchinfoPager), new FrameworkPropertyMetadata(typeof(MuchinfoPager))); } public MuchinfoPager() { this.Loaded += MuchinfoPager_Loaded; } #endregion #region Methods private static void OnPageIndexPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { var pager = (MuchinfoPager)d; if (pager.IsInitializingData) { return; } if (pager._areHandlersSuspended) { return; } pager.UpdateReadonlyProperties(); pager.ExecuteCommand(); } private void CheckPageIndexChange(int oldPageIndex, int newPageIndex) { if (this.PageSize == 0 && newPageIndex != -1) { this.SetValueNoCallback(MuchinfoPager.PageIndexProperty, oldPageIndex); throw new ArgumentOutOfRangeException("newPageIndex", "PageIndex can only be set to -1 when the PageSize is 0."); } if (this.PageSize != 0 && newPageIndex == -1) { this.SetValueNoCallback(MuchinfoPager.PageIndexProperty, oldPageIndex); throw new ArgumentOutOfRangeException("newPageIndex", "PageIndex cannot be negative when PageSize is positive."); } } private static bool IsValidDataPagerIndex(object value) { return (int)value >= -1; } private static void OnPageSizePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { var pager = (MuchinfoPager)d; if (pager.IsInitializingData) { return; } pager.UpdatePageCount(); pager.UpdateReadonlyProperties(); pager.ExecuteCommand(); } private static void OnItemCountPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { var pager = (MuchinfoPager)d; if (pager.IsInitializingData) { return; } pager.UpdatePageCount(); pager.UpdateReadonlyProperties(); //此处调用Command会触发两次查询, 因为PageIndex改变也会触发 //pager.ExecuteCommand(); } public bool MoveToFirstPage() { if (PageCount > 0) PageIndex = 0; return true; } public bool MoveToLastPage() { if (PageCount > 0) PageIndex = PageCount - 1; return true; } public bool MoveToNextPage() { if (PageCount > 0 && PageIndex < PageCount - 1) PageIndex = PageIndex + 1; return true; } public bool MoveToPage(int pageIndex) { if (pageIndex < 0) { PageIndex = 0; } else if (pageIndex > PageCount) { PageIndex = PageCount - 1; } else { PageIndex = pageIndex; } return true; } public bool MoveToPreviousPage() { if (PageCount > 0 && PageIndex > 0) PageIndex = PageIndex - 1; return true; } private void SetValueNoCallback(DependencyProperty property, object value) { this._areHandlersSuspended = true; try { base.SetValue(property, value); } finally { this._areHandlersSuspended = false; } } private void UpdatePageCount() { if (ItemCount > 0 && PageIndex < 0) PageIndex = 0; this.PageCount = Math.Max(1, (int)Math.Ceiling((double)ItemCount / (double)PageSize)); } private void UpdateReadonlyProperties() { var canChangePage = ItemCount > 0; CanChangePage = canChangePage; CanMoveToFirstPage = canChangePage && this.PageIndex > 0; CanMoveToLastPage = canChangePage && this.PageIndex < this.PageCount - 1; CanMoveToPreviousPage = canChangePage && this.PageIndex > 0; CanMoveToNextPage = canChangePage && this.PageIndex < this.PageCount - 1; CommandManager.InvalidateRequerySuggested(); } #endregion #region Override Handle public override void BeginInit() { base.BeginInit(); this.BeginInitInternal(); } //public override void EndInit() //{ // this.EndInitInternal(); // base.EndInit(); //} private void MuchinfoPager_Loaded(object sender, RoutedEventArgs e) { //使用loaded代替EndInit,界面绑定值时会触发查询 this.EndInitInternal(); } private void BeginInitInternal() { this._initializingData = new bool?(true); } private void EndInitInternal() { this._initializingData = new bool?(false); UpdatePageCount(); UpdateReadonlyProperties(); } #endregion #region ICommand public static readonly DependencyProperty CommandParameterProperty = DependencyProperty.Register("CommandParameter", typeof(object), typeof(MuchinfoPager), new PropertyMetadata(null)); public static readonly DependencyProperty CommandProperty = DependencyProperty.Register("Command", typeof(ICommand), typeof(MuchinfoPager), new PropertyMetadata(null)); public static readonly DependencyProperty CommandTargetProperty = DependencyProperty.Register("CommandTarget", typeof(UIElement), typeof(MuchinfoPager), null); [TypeConverter(typeof(CommandConverter))] public ICommand Command { get { return (ICommand)base.GetValue(MuchinfoPager.CommandProperty); } set { base.SetValue(MuchinfoPager.CommandProperty, value); } } public object CommandParameter { get { return base.GetValue(MuchinfoPager.CommandParameterProperty); } set { base.SetValue(MuchinfoPager.CommandParameterProperty, value); } } public IInputElement CommandTarget { get { return null; } } private void ExecuteCommand() { if (PageIndex < 0) return; if (this.Command != null) { var routedCommand = this.Command as RoutedCommand; if (routedCommand == null) { this.Command.Execute(this.CommandParameter); return; } routedCommand.Execute(this.CommandParameter, this.CommandTarget ?? this); } } #endregion } }