diff --git a/demo/Ursa.Demo/Pages/PaginationDemo.axaml b/demo/Ursa.Demo/Pages/PaginationDemo.axaml
index 9af5f60..ab087ef 100644
--- a/demo/Ursa.Demo/Pages/PaginationDemo.axaml
+++ b/demo/Ursa.Demo/Pages/PaginationDemo.axaml
@@ -17,6 +17,6 @@
+ TotalCount="600" />
diff --git a/src/Ursa.Themes.Semi/Controls/Pagination.axaml b/src/Ursa.Themes.Semi/Controls/Pagination.axaml
index 03cd756..039c857 100644
--- a/src/Ursa.Themes.Semi/Controls/Pagination.axaml
+++ b/src/Ursa.Themes.Semi/Controls/Pagination.axaml
@@ -2,14 +2,29 @@
xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:u="https://irihi.tech/ursa">
+
+
+
+
+
-
-
+
+
+
+
+
+
-
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Ursa.Themes.Semi/Themes/Dark/Pagination.axaml b/src/Ursa.Themes.Semi/Themes/Dark/Pagination.axaml
new file mode 100644
index 0000000..9017e8d
--- /dev/null
+++ b/src/Ursa.Themes.Semi/Themes/Dark/Pagination.axaml
@@ -0,0 +1,3 @@
+
+
+
diff --git a/src/Ursa.Themes.Semi/Themes/Dark/_index.axaml b/src/Ursa.Themes.Semi/Themes/Dark/_index.axaml
index 004d6a1..69dc5ed 100644
--- a/src/Ursa.Themes.Semi/Themes/Dark/_index.axaml
+++ b/src/Ursa.Themes.Semi/Themes/Dark/_index.axaml
@@ -5,6 +5,7 @@
+
diff --git a/src/Ursa.Themes.Semi/Themes/Light/Pagination.axaml b/src/Ursa.Themes.Semi/Themes/Light/Pagination.axaml
new file mode 100644
index 0000000..9017e8d
--- /dev/null
+++ b/src/Ursa.Themes.Semi/Themes/Light/Pagination.axaml
@@ -0,0 +1,3 @@
+
+
+
diff --git a/src/Ursa.Themes.Semi/Themes/Light/_index.axaml b/src/Ursa.Themes.Semi/Themes/Light/_index.axaml
index 004d6a1..69dc5ed 100644
--- a/src/Ursa.Themes.Semi/Themes/Light/_index.axaml
+++ b/src/Ursa.Themes.Semi/Themes/Light/_index.axaml
@@ -5,6 +5,7 @@
+
diff --git a/src/Ursa.Themes.Semi/Themes/Shared/Pagination.axaml b/src/Ursa.Themes.Semi/Themes/Shared/Pagination.axaml
new file mode 100644
index 0000000..dd66176
--- /dev/null
+++ b/src/Ursa.Themes.Semi/Themes/Shared/Pagination.axaml
@@ -0,0 +1,7 @@
+
+
+ M12.6185 4.39653C13.1272 4.92524 13.1272 5.78245 12.6185 6.31116L7.14483 12L12.6185 17.6888C13.1272 18.2176 13.1272 19.0748 12.6185 19.6035C12.1098 20.1322 11.285 20.1322 10.7763 19.6035L4.38153 12.9573C3.87282 12.4286 3.87282 11.5714 4.38153 11.0427L10.7763 4.39653C11.285 3.86782 12.1098 3.86782 12.6185 4.39653Z M19.6185 4.39653C20.1272 4.92524 20.1272 5.78245 19.6185 6.31116L14.1448 12L19.6185 17.6888C20.1272 18.2176 20.1272 19.0748 19.6185 19.6035C19.1098 20.1322 18.285 20.1322 17.7763 19.6035L11.3815 12.9573C10.8728 12.4286 10.8728 11.5714 11.3815 11.0427L17.7763 4.39653C18.285 3.86782 19.1098 3.86782 19.6185 4.39653Z
+ M4.38153 4.39653C4.89024 3.86782 5.71502 3.86782 6.22373 4.39653L12.6185 11.0427C13.1272 11.5714 13.1272 12.4286 12.6185 12.9573L6.22373 19.6035C5.71502 20.1322 4.89024 20.1322 4.38153 19.6035C3.87282 19.0748 3.87282 18.2176 4.38153 17.6888L9.85517 12L4.38153 6.31116C3.87282 5.78245 3.87282 4.92524 4.38153 4.39653Z M11.3815 4.39653C11.8902 3.86782 12.715 3.86782 13.2237 4.39653L19.6185 11.0427C20.1272 11.5714 20.1272 12.4286 19.6185 12.9573L13.2237 19.6035C12.715 20.1322 11.8902 20.1322 11.3815 19.6035C10.8728 19.0748 10.8728 18.2176 11.3815 17.6888L16.8552 12L11.3815 6.31116C10.8728 5.78245 10.8728 4.92524 11.3815 4.39653Z
+ M7.43934 19.7957C6.85355 19.2099 6.85355 18.2601 7.43934 17.6744L13.0962 12.0175L7.43934 6.36065C6.85355 5.77486 6.85355 4.82511 7.43934 4.23933C8.02513 3.65354 8.97487 3.65354 9.56066 4.23933L16.2782 10.9568C16.864 11.5426 16.864 12.4924 16.2782 13.0782L9.56066 19.7957C8.97487 20.3815 8.02513 20.3815 7.43934 19.7957Z
+ M16.2782 4.23933C16.864 4.82511 16.864 5.77486 16.2782 6.36065L10.6213 12.0175L16.2782 17.6744C16.864 18.2601 16.864 19.2099 16.2782 19.7957C15.6924 20.3815 14.7426 20.3815 14.1569 19.7957L7.43934 13.0782C6.85355 12.4924 6.85355 11.5426 7.43934 10.9568L14.1569 4.23933C14.7426 3.65354 15.6924 3.65354 16.2782 4.23933Z
+
diff --git a/src/Ursa.Themes.Semi/Themes/Shared/_index.axaml b/src/Ursa.Themes.Semi/Themes/Shared/_index.axaml
index 7a530cc..5d9a332 100644
--- a/src/Ursa.Themes.Semi/Themes/Shared/_index.axaml
+++ b/src/Ursa.Themes.Semi/Themes/Shared/_index.axaml
@@ -5,5 +5,6 @@
+
diff --git a/src/Ursa/Controls/Pagination/Pagination.cs b/src/Ursa/Controls/Pagination/Pagination.cs
index 002985a..0b71333 100644
--- a/src/Ursa/Controls/Pagination/Pagination.cs
+++ b/src/Ursa/Controls/Pagination/Pagination.cs
@@ -8,6 +8,11 @@ using Avalonia.Styling;
namespace Ursa.Controls;
+///
+/// Pagination is a control that displays a series of buttons that can be used to navigate to pages.
+/// CurrentPage starts from 1.
+/// Pagination only stores an approximate index internally.
+///
[TemplatePart(PART_PreviousButton, typeof(Button))]
[TemplatePart(PART_NextButton, typeof(Button))]
[TemplatePart(PART_ButtonPanel, typeof(StackPanel))]
@@ -21,14 +26,9 @@ public class Pagination: TemplatedControl
private Button? _previousButton;
private Button? _nextButton;
private StackPanel? _buttonPanel;
+ private readonly PaginationButton[] _buttons = new PaginationButton[7];
private ComboBox? _sizeChangerComboBox;
- ///
- /// To reduce allocation, there are maximum of 7 buttons and 2 selection controls. it will be reused.
- ///
- private PaginationExpandButton? _leftSelection;
- private PaginationExpandButton? _rightSelection;
-
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
{
base.OnApplyTemplate(e);
@@ -40,9 +40,8 @@ public class Pagination: TemplatedControl
_sizeChangerComboBox = e.NameScope.Find(PART_SizeChangerComboBox);
if (_previousButton != null) _previousButton.Click += OnButtonClick;
if (_nextButton != null) _nextButton.Click += OnButtonClick;
- _leftSelection = new PaginationExpandButton();
- _rightSelection = new PaginationExpandButton();
- UpdateButtons();
+ InitializePanelButtons();
+ UpdateButtons(0);
}
@@ -111,21 +110,20 @@ public class Pagination: TemplatedControl
set => SetValue(PageButtonThemeProperty, value);
}
- public static readonly StyledProperty ExpandButtonThemeProperty = AvaloniaProperty.Register(
- nameof(ExpandButtonTheme));
-
- public ControlTheme ExpandButtonTheme
- {
- get => GetValue(ExpandButtonThemeProperty);
- set => SetValue(ExpandButtonThemeProperty, value);
- }
-
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
{
base.OnPropertyChanged(change);
- if (change.Property == PageSizeProperty || change.Property == TotalCountProperty)
+ // When page size is updated, the selected current page must be updated.
+ if (change.Property == PageSizeProperty)
{
- UpdateButtons();
+ int oldPageSize = change.GetOldValue();
+ int index = oldPageSize * CurrentPage;
+ UpdateButtons(index);
+ }
+ else if (change.Property == TotalCountProperty || change.Property == CurrentPageProperty)
+ {
+ int index = PageSize * CurrentPage;
+ UpdateButtons(index);
}
}
@@ -133,18 +131,60 @@ public class Pagination: TemplatedControl
{
if (Equals(sender, _previousButton))
{
- CurrentPage--;
+ AddCurrentPage(-1);
}
else
{
- CurrentPage++;
+ AddCurrentPage(1);
}
}
- private void UpdateButtons()
+ private void InitializePanelButtons()
{
+ if (_buttonPanel is null) return;
+ _buttonPanel.Children.Clear();
+ for (int i = 1; i <= 7; i++)
+ {
+ var button = new PaginationButton() { Page = i, IsVisible = true };
+ _buttonPanel.Children.Add(button);
+ _buttons![i - 1] = button;
+ button.Click+= OnPageButtonClick;
+ }
+ }
+
+ private void OnPageButtonClick(object sender, RoutedEventArgs args)
+ {
+ if (sender is PaginationButton pageButton)
+ {
+ if (pageButton.IsLeftForward)
+ {
+ AddCurrentPage(-5);
+ }
+ else if (pageButton.IsRightForward)
+ {
+ AddCurrentPage(5);
+ }
+ else
+ {
+ CurrentPage = pageButton.Page;
+ }
+ }
+ }
+
+ private void AddCurrentPage(int pageChange)
+ {
+ int newValue = CurrentPage + pageChange;
+ if (newValue <= 0) newValue = 1;
+ else if(newValue>=PageCount) newValue = PageCount;
+ CurrentPage = newValue;
+ }
+
+ private void UpdateButtons(int index)
+ {
+ if (_buttonPanel is null) return;
if (PageSize == 0) return;
- int currentIndex = CurrentPage * PageSize;
+
+ int currentIndex = index;
int pageCount = TotalCount / PageSize;
int residue = TotalCount % PageSize;
@@ -152,18 +192,71 @@ public class Pagination: TemplatedControl
{
pageCount++;
}
- _buttonPanel?.Children.Clear();
- for (int i = 0; i < pageCount; i++)
+
+ PageCount = pageCount;
+
+ int currentPage = currentIndex/ PageSize;
+ if (currentPage == 0) currentPage++;
+
+ if (pageCount <= 7)
{
- if (i == 1 && _leftSelection is not null)
+ for (int i = 0; i < 7; i++)
{
- _leftSelection.Pages = new AvaloniaList() { PageSize + 1, PageSize + 2, PageSize + 3 };
- _buttonPanel?.Children.Add(_leftSelection);
+ if (i < pageCount)
+ {
+ _buttons[i].IsVisible = true;
+ _buttons[i].SetStatus(i + 1, i+1 == CurrentPage, false, false);
+ }
+ else
+ {
+ _buttons[i].IsVisible = false;
+ }
+ }
+ }
+ else
+ {
+ for (int i = 0; i < 7; i++)
+ {
+ _buttons[i].IsVisible = true;
+ }
+ int mid = currentPage;
+ if (mid < 4) mid = 4;
+ else if (mid > pageCount - 3) mid = pageCount - 3;
+ _buttons[3].Page = mid;
+ _buttons[2].Page = mid - 1;
+ _buttons[4].Page = mid + 1;
+ _buttons[0].Page = 1;
+ _buttons[6].Page = pageCount;
+ if(mid>4)
+ {
+ _buttons[1].SetStatus(0, false, true, false);
}
else
{
- _buttonPanel?.Children.Add(new PaginationButton { Content = i + 1, Page = i + 1 });
+ _buttons[1].SetStatus(mid-2, false, false, false);
+ }
+ if(mid typeof(Button);
-
- public int Page { get; set; }
-
+ public const string PC_Left = ":left";
+ public const string PC_Right = ":right";
+ public const string PC_Selected = ":selected";
+
+ public static readonly StyledProperty PageProperty = AvaloniaProperty.Register(
+ nameof(Page));
+
+ public int Page
+ {
+ get => GetValue(PageProperty);
+ set => SetValue(PageProperty, value);
+ }
+ public bool IsLeftForward { get; private set; }
+ public bool IsRightForward { get; private set; }
+ internal void SetStatus(int page, bool isSelected, bool isLeft, bool isRight)
+ {
+ PseudoClasses.Set(PC_Selected, isSelected);
+ PseudoClasses.Set(PC_Left, isLeft);
+ PseudoClasses.Set(PC_Right, isRight);
+ IsLeftForward = isLeft;
+ IsRightForward = isRight;
+ Page = page;
+ }
+
+ internal void SetSelected(bool isSelected)
+ {
+ PseudoClasses.Set(PC_Selected, isSelected);
+ }
}
\ No newline at end of file
diff --git a/src/Ursa/Controls/Pagination/PaginationExpandButton.cs b/src/Ursa/Controls/Pagination/PaginationExpandButton.cs
deleted file mode 100644
index fb50a59..0000000
--- a/src/Ursa/Controls/Pagination/PaginationExpandButton.cs
+++ /dev/null
@@ -1,79 +0,0 @@
-using Avalonia;
-using Avalonia.Collections;
-using Avalonia.Controls;
-using Avalonia.Controls.Metadata;
-using Avalonia.Controls.Primitives;
-using Avalonia.Input;
-
-namespace Ursa.Controls;
-
-[TemplatePart(PART_Button, typeof(Button))]
-[TemplatePart(PART_Popup, typeof(Popup))]
-public class PaginationExpandButton: TemplatedControl
-{
- public const string PART_Button = "PART_Button";
- public const string PART_Popup = "PART_Popup";
- private Popup? _popup;
- private Button? _button;
-
- public static readonly StyledProperty> PagesProperty = AvaloniaProperty.Register>(
- nameof(Pages));
-
- public AvaloniaList Pages
- {
- get => GetValue(PagesProperty);
- set => SetValue(PagesProperty, value);
- }
-
- public static readonly StyledProperty IsDropdownOpenProperty = AvaloniaProperty.Register(
- nameof(IsDropdownOpen));
-
- public bool IsDropdownOpen
- {
- get => GetValue(IsDropdownOpenProperty);
- set => SetValue(IsDropdownOpenProperty, value);
- }
-
- protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
- {
- base.OnApplyTemplate(e);
- _popup = e.NameScope.Find(PART_Popup);
- _button = e.NameScope.Find