diff --git a/demo/Semi.Avalonia.Demo/Pages/CarouselPageDemo.axaml b/demo/Semi.Avalonia.Demo/Pages/CarouselPageDemo.axaml
new file mode 100644
index 0000000..d736ef0
--- /dev/null
+++ b/demo/Semi.Avalonia.Demo/Pages/CarouselPageDemo.axaml
@@ -0,0 +1,69 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/demo/Semi.Avalonia.Demo/Pages/CarouselPageDemo.axaml.cs b/demo/Semi.Avalonia.Demo/Pages/CarouselPageDemo.axaml.cs
new file mode 100644
index 0000000..672f242
--- /dev/null
+++ b/demo/Semi.Avalonia.Demo/Pages/CarouselPageDemo.axaml.cs
@@ -0,0 +1,34 @@
+using System.Collections;
+using Avalonia.Controls;
+using Avalonia.Interactivity;
+
+namespace Semi.Avalonia.Demo.Pages;
+
+public partial class CarouselPageDemo : UserControl
+{
+ public CarouselPageDemo()
+ {
+ InitializeComponent();
+ }
+
+ private void OnPrevious(object? sender, RoutedEventArgs e)
+ {
+ if (DemoCarousel.SelectedIndex > 0)
+ DemoCarousel.SelectedIndex--;
+ }
+
+ private void OnNext(object? sender, RoutedEventArgs e)
+ {
+ var pageCount = (DemoCarousel.Pages as IList)?.Count ?? 0;
+ if (DemoCarousel.SelectedIndex < pageCount - 1)
+ DemoCarousel.SelectedIndex++;
+ }
+
+ private void OnSelectionChanged(object? sender, PageSelectionChangedEventArgs e)
+ {
+ if (StatusText == null)
+ return;
+ var pageCount = (DemoCarousel.Pages as IList)?.Count ?? 0;
+ StatusText.Text = $"Page {DemoCarousel.SelectedIndex + 1} of {pageCount}";
+ }
+}
\ No newline at end of file
diff --git a/demo/Semi.Avalonia.Demo/Pages/PipsPagerDemo.axaml b/demo/Semi.Avalonia.Demo/Pages/PipsPagerDemo.axaml
new file mode 100644
index 0000000..1e74885
--- /dev/null
+++ b/demo/Semi.Avalonia.Demo/Pages/PipsPagerDemo.axaml
@@ -0,0 +1,99 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/demo/Semi.Avalonia.Demo/Pages/PipsPagerDemo.axaml.cs b/demo/Semi.Avalonia.Demo/Pages/PipsPagerDemo.axaml.cs
new file mode 100644
index 0000000..1247fc4
--- /dev/null
+++ b/demo/Semi.Avalonia.Demo/Pages/PipsPagerDemo.axaml.cs
@@ -0,0 +1,12 @@
+using Avalonia.Controls;
+
+namespace Semi.Avalonia.Demo.Pages;
+
+public partial class PipsPagerDemo : UserControl
+{
+ public PipsPagerDemo()
+ {
+ InitializeComponent();
+ }
+}
+
diff --git a/demo/Semi.Avalonia.Demo/Views/MainView.axaml b/demo/Semi.Avalonia.Demo/Views/MainView.axaml
index 0a6d806..d8d48d0 100644
--- a/demo/Semi.Avalonia.Demo/Views/MainView.axaml
+++ b/demo/Semi.Avalonia.Demo/Views/MainView.axaml
@@ -200,6 +200,9 @@
+
+
+
@@ -222,6 +225,9 @@
+
+
+
diff --git a/src/Semi.Avalonia/Controls/Carousel.axaml b/src/Semi.Avalonia/Controls/Carousel.axaml
index d07459a..8bf031b 100644
--- a/src/Semi.Avalonia/Controls/Carousel.axaml
+++ b/src/Semi.Avalonia/Controls/Carousel.axaml
@@ -156,7 +156,7 @@
Theme="{DynamicResource InnerPathIcon}"
Width="{TemplateBinding Width}"
Height="{TemplateBinding Height}"
- Data="{DynamicResource CarouselButtonGlyph}"
+ Data="{TemplateBinding Content}"
Foreground="{TemplateBinding Foreground}" />
@@ -213,6 +213,7 @@
Theme="{DynamicResource CarouselButton}"
Margin="{DynamicResource CarouselButtonMargin}"
Foreground="{DynamicResource CarouselButtonForeground}"
+ Content="{StaticResource SemiIconChevronLeft}"
IsVisible="{TemplateBinding ItemCount, Converter={x:Static semi:ItemConverter.ItemVisibleConverter}}"
Command="{Binding $parent[Carousel].Previous}" />
+ Command="{Binding $parent[Carousel].Next}" />
diff --git a/src/Semi.Avalonia/Controls/CarouselPage.axaml b/src/Semi.Avalonia/Controls/CarouselPage.axaml
new file mode 100644
index 0000000..1e6da26
--- /dev/null
+++ b/src/Semi.Avalonia/Controls/CarouselPage.axaml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Semi.Avalonia/Controls/PipsPager.axaml b/src/Semi.Avalonia/Controls/PipsPager.axaml
new file mode 100644
index 0000000..54d0d38
--- /dev/null
+++ b/src/Semi.Avalonia/Controls/PipsPager.axaml
@@ -0,0 +1,130 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Semi.Avalonia/Controls/_index.axaml b/src/Semi.Avalonia/Controls/_index.axaml
index 7b389c8..612ab61 100644
--- a/src/Semi.Avalonia/Controls/_index.axaml
+++ b/src/Semi.Avalonia/Controls/_index.axaml
@@ -11,6 +11,7 @@
+
@@ -37,6 +38,7 @@
+
diff --git a/src/Semi.Avalonia/Themes/Dark/PipsPager.axaml b/src/Semi.Avalonia/Themes/Dark/PipsPager.axaml
new file mode 100644
index 0000000..7912e2c
--- /dev/null
+++ b/src/Semi.Avalonia/Themes/Dark/PipsPager.axaml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
diff --git a/src/Semi.Avalonia/Themes/Dark/_index.axaml b/src/Semi.Avalonia/Themes/Dark/_index.axaml
index c74719b..6210d7f 100644
--- a/src/Semi.Avalonia/Themes/Dark/_index.axaml
+++ b/src/Semi.Avalonia/Themes/Dark/_index.axaml
@@ -29,6 +29,7 @@
+
diff --git a/src/Semi.Avalonia/Themes/HighContrast/PipsPager.axaml b/src/Semi.Avalonia/Themes/HighContrast/PipsPager.axaml
new file mode 100644
index 0000000..aad2704
--- /dev/null
+++ b/src/Semi.Avalonia/Themes/HighContrast/PipsPager.axaml
@@ -0,0 +1,4 @@
+
+
+
diff --git a/src/Semi.Avalonia/Themes/HighContrast/_index.axaml b/src/Semi.Avalonia/Themes/HighContrast/_index.axaml
index 04ed1ec..9211573 100644
--- a/src/Semi.Avalonia/Themes/HighContrast/_index.axaml
+++ b/src/Semi.Avalonia/Themes/HighContrast/_index.axaml
@@ -29,6 +29,7 @@
+
diff --git a/src/Semi.Avalonia/Themes/Light/PipsPager.axaml b/src/Semi.Avalonia/Themes/Light/PipsPager.axaml
new file mode 100644
index 0000000..b395b75
--- /dev/null
+++ b/src/Semi.Avalonia/Themes/Light/PipsPager.axaml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
diff --git a/src/Semi.Avalonia/Themes/Light/_index.axaml b/src/Semi.Avalonia/Themes/Light/_index.axaml
index c74719b..6210d7f 100644
--- a/src/Semi.Avalonia/Themes/Light/_index.axaml
+++ b/src/Semi.Avalonia/Themes/Light/_index.axaml
@@ -29,6 +29,7 @@
+