改造他人的分页控件,先看效果图
主要代码有两个,Pagination.cs ,Pagination.xaml,其中用到了第三方开源控件HandyControl的样式
Pagination.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
namespace King_E.ARMS.Client.UserControls.Pagination
{
[TemplatePart(Name = CountPerPageComboBoxTemplateName, Type = typeof(ComboBox))]
[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 CountPerPageComboBoxTemplateName = "PART_CountPerPageCount";
private const string JustPageTextBoxTemplateName = "PART_JumpPageTextBox";
private const string ListBoxTemplateName = "PART_ListBox";
private const string Ellipsis = "...";
private static readonly Type _typeofSelf = typeof(Pagination);
private ComboBox _countPerPageComboBox;
private TextBox _jumpPageTextBox;
private ListBox _listBox;
static Pagination()
{
InitializeCommands();
DefaultStyleKeyProperty.OverrideMetadata(_typeofSelf, new FrameworkPropertyMetadata(_typeofSelf));
}
#region Override
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
UnsubscribeEvents();
_countPerPageComboBox = GetTemplateChild(CountPerPageComboBoxTemplateName) as ComboBox;
if (_countPerPageComboBox != null)
{
_countPerPageComboBox.ContextMenu = null;
}
_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 = true;// 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 PageRecordCountPropertyKey =
DependencyProperty.RegisterReadOnly("PageRecordCount", typeof(IEnumerable<int>), _typeofSelf,
new PropertyMetadata(null));
public static readonly DependencyProperty PageRecordCountProperty = PageRecordCountPropertyKey.DependencyProperty;
public IEnumerable<int> PageRecordCount
{
get => (IEnumerable<int>)GetValue(PageRecordCountProperty);
set {
SetValue(PageRecordCountProperty, value);
}
}
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(10, OnCountPerPagePropertyChanged, CoerceCountPerPage));
public int CountPerPage
{
get => (int)GetValue(CountPerPageProperty);
set
{
SetValue(CountPerPageProperty, value);
RaiseCountPerPageChangedEvent(value);
RaiseCurrentPageChangedEvent(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._countPerPageComboBox != null)
ctrl._countPerPageComboBox.SelectedItem = countPerPage;
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);
RaiseCurrentPageChangedEvent(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
// 定义事件声明
public static readonly RoutedEvent CountPerPageChangedEvent = EventManager.RegisterRoutedEvent(
"CountPerPageChanged", RoutingStrategy.Bubble, typeof(RoutedEventHandler), _typeofSelf);
// 属性包装事件
public event RoutedEventHandler CountPerPageChanged
{
add { AddHandler(CountPerPageChangedEvent, value); }
remove { RemoveHandler(CountPerPageChangedEvent, value); }
}
// 触发事件的方法
public void RaiseCountPerPageChangedEvent(object source)
{
RoutedEventArgs newEventArgs = new RoutedEventArgs(CountPerPageChangedEvent,source);
RaiseEvent(newEventArgs);
}
// 定义事件声明
public static readonly RoutedEvent CurrentPageChangedEvent = EventManager.RegisterRoutedEvent(
"CurrentPageChanged", RoutingStrategy.Bubble, typeof(RoutedEventHandler), _typeofSelf);
// 属性包装事件
public event RoutedEventHandler CurrentPageChanged
{
add { AddHandler(CurrentPageChangedEvent, value); }
remove { RemoveHandler(CurrentPageChangedEvent, value); }
}
// 触发事件的方法
public void RaiseCurrentPageChangedEvent(object source)
{
RoutedEventArgs newEventArgs = new RoutedEventArgs(CurrentPageChangedEvent,source);
RaiseEvent(newEventArgs);
}
/// <summary>
/// 分页
/// </summary>
private void OnCountPerPageComboBoxSelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (int.TryParse(_countPerPageComboBox.SelectedItem.ToString(), 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;
_countPerPageComboBox.SelectedItem = CountPerPage;
if (_listBox != null)
_listBox.SelectedItem = Current.ToString();
}
private void UnsubscribeEvents()
{
if (_countPerPageComboBox != null)
_countPerPageComboBox.SelectionChanged -= OnCountPerPageComboBoxSelectionChanged;
if (_jumpPageTextBox != null)
_jumpPageTextBox.TextChanged -= OnJumpPageTextBoxChanged;
if (_listBox != null)
_listBox.SelectionChanged -= OnSelectionChanged;
}
private void SubscribeEvents()
{
if (_countPerPageComboBox != null)
_countPerPageComboBox.SelectionChanged += OnCountPerPageComboBoxSelectionChanged;
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
}
}
Pagination.xaml
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
xmlns:input="clr-namespace:System.Windows.Input;assembly=PresentationCore"
xmlns:controls="clr-namespace:King_E.ARMS.Client.UserControls.Pagination">
<x:Array Type="{x:Type sys:Int32}" x:Key="IEnumerableInts">
<sys:Int32>10</sys:Int32>
<sys:Int32>15</sys:Int32>
<sys:Int32>20</sys:Int32>
<sys:Int32>25</sys:Int32>
<sys:Int32>30</sys:Int32>
<sys:Int32>40</sys:Int32>
<sys:Int32>50</sys:Int32>
<sys:Int32>100</sys:Int32>
<sys:Int32>200</sys:Int32>
<sys:Int32>300</sys:Int32>
</x:Array>
<Style x:Key="PageListBoxStyleKey" TargetType="{x:Type ListBox}" >
<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}" >
<Setter Property="Width" Value="28"/>
<Setter Property="Height" Value="28"/>
<Setter Property="Cursor" Value="Hand"/>
<Setter Property="HorizontalContentAlignment" Value="Center"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="Padding" Value="5,0"/>
<Setter Property="Margin" Value="3,0"/>
<Setter Property="Background" Value="{StaticResource BackgroundBrush}"/>
<Setter Property="BorderBrush" Value="{StaticResource BorderBrush}"/>
<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="3">
<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="{StaticResource BorderBrush}"/>
<Setter Property="Background" Value="{StaticResource PrimaryBrush}"/>
<Setter Property="Foreground" Value="White"/>
</Trigger>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Background" Value="{StaticResource PrimaryBrush}"/>
<Setter Property="TextElement.Foreground" Value="White"/>
</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}}"/>
<ComboBox Grid.Column="2" x:Name="PART_CountPerPageCount"
VerticalAlignment="Center"
Width="60" VerticalContentAlignment="Center"
ItemsSource="{DynamicResource IEnumerableInts}"/>
<TextBlock Grid.Column="3" Text=" 条 / 页" VerticalAlignment="Center"/>
<Button Grid.Column="5" Foreground="White"
Content="<"
Command="{x:Static controls:Pagination.PrevCommand}">
</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" Foreground="White"
Content=">"
Command="{x:Static controls:Pagination.NextCommand}">
</Button>
</Grid>
</Border>
</ControlTemplate>
<Style TargetType="{x:Type controls:Pagination}" >
<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"/>
<ComboBox Grid.Column="2" x:Name="PART_CountPerPageCount"
VerticalAlignment="Center"
Width="60" VerticalContentAlignment="Center"
ItemsSource="{DynamicResource IEnumerableInts}"/>
<TextBlock Text=" 条" VerticalAlignment="Center"/>
</StackPanel>
<Button Grid.Column="2" Foreground="White"
Content="<" Style="{StaticResource ButtonPrimary}"
Command="{x:Static controls:Pagination.PrevCommand}">
</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" Foreground="White"
Content=">" Style="{StaticResource ButtonPrimary}"
Command="{x:Static controls:Pagination.NextCommand}">
</Button>
<StackPanel Grid.Column="5" Orientation="Horizontal" Visibility="Hidden">
<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>