# 所用到的關鍵知識點
① 自定義使用者控件 (整個Page 是一個用自定義使用者控件)
② 自定義控件 (每一個頁面小按鍵是自定義控件)
③ 樣式觸發器 (Buttontype 改變時自動切換控件模闆)
④ 自定義事件給引用者使用 (當點選每個頁面按鍵時觸發)
⑤ 依賴項屬性 以及 屬性改變回調事件
⑥ 其它
#開發和運作階段的效果圖檔
1、開發時效果圖

2、運作時的效果圖
運作時效果
# 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 預設就顯示些控件 如上一面 首頁 這些不需要動态生成的,主要為了性能的考慮 。
如果這些控件也動态生成,可能後端代碼會少很多。
好久沒有好好的搞代碼拉,花了整整兩天的時間。不足之處歡迎指出,也希望能幫到一些朋面。