|
After Width: | Height: | Size: 406 KiB |
|
After Width: | Height: | Size: 450 KiB |
|
After Width: | Height: | Size: 457 KiB |
|
After Width: | Height: | Size: 525 KiB |
|
After Width: | Height: | Size: 324 KiB |
|
After Width: | Height: | Size: 455 KiB |
|
After Width: | Height: | Size: 407 KiB |
@ -0,0 +1,11 @@ |
|||||
|
<UserControl xmlns="https://github.com/avaloniaui" |
||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" |
||||
|
x:Class="ControlCatalog.Pages.CarouselDemoPage"> |
||||
|
<NavigationPage x:Name="SampleNav"> |
||||
|
<NavigationPage.Styles> |
||||
|
<Style Selector="NavigationPage#SampleNav /template/ Border#PART_NavigationBar"> |
||||
|
<Setter Property="Background" Value="Transparent" /> |
||||
|
</Style> |
||||
|
</NavigationPage.Styles> |
||||
|
</NavigationPage> |
||||
|
</UserControl> |
||||
@ -0,0 +1,91 @@ |
|||||
|
using System; |
||||
|
using Avalonia.Controls; |
||||
|
using Avalonia.Interactivity; |
||||
|
|
||||
|
namespace ControlCatalog.Pages |
||||
|
{ |
||||
|
public partial class CarouselDemoPage : UserControl |
||||
|
{ |
||||
|
private static readonly (string Group, string Title, string Description, Func<UserControl> Factory)[] Demos = |
||||
|
{ |
||||
|
// Overview
|
||||
|
("Overview", "First Look", |
||||
|
"Basic CarouselPage with three pages and page indicator.", |
||||
|
() => new CarouselPageFirstLookPage()), |
||||
|
|
||||
|
// Populate
|
||||
|
("Populate", "Data Templates", |
||||
|
"Bind CarouselPage to an ObservableCollection, add or remove pages at runtime, and switch the page template.", |
||||
|
() => new CarouselPageDataTemplatePage()), |
||||
|
|
||||
|
// Appearance
|
||||
|
("Appearance", "Customization", |
||||
|
"Switch slide direction between horizontal and vertical with PageSlide. Page indicator dots update on each selection.", |
||||
|
() => new CarouselPageCustomizationPage()), |
||||
|
|
||||
|
// Features
|
||||
|
("Features", "Page Transitions", |
||||
|
"Animate page switches with CrossFade or PageSlide.", |
||||
|
() => new CarouselPageTransitionsPage()), |
||||
|
("Features", "Programmatic Selection", |
||||
|
"Jump to any page programmatically with SelectedIndex and respond to SelectionChanged events.", |
||||
|
() => new CarouselPageSelectionPage()), |
||||
|
("Features", "Gesture & Keyboard", |
||||
|
"Swipe left/right to navigate pages. Toggle IsGestureEnabled and IsKeyboardNavigationEnabled.", |
||||
|
() => new CarouselPageGesturePage()), |
||||
|
("Features", "Events", |
||||
|
"SelectionChanged, NavigatedTo, and NavigatedFrom events. Swipe or navigate to see the live event log.", |
||||
|
() => new CarouselPageEventsPage()), |
||||
|
|
||||
|
// Performance
|
||||
|
("Performance", "Performance Monitor", |
||||
|
"Track page count, live page instances, and managed heap size. Observe how GC reclaims memory after removing pages.", |
||||
|
() => new CarouselPagePerformancePage()), |
||||
|
|
||||
|
// Showcases
|
||||
|
("Showcases", "Sanctuary", |
||||
|
"Travel discovery app with 3 full-screen immersive pages. Each page has a real background photo, gradient overlay, and themed content. Built as a 1:1 replica of a Stitch design.", |
||||
|
() => new SanctuaryShowcasePage()), |
||||
|
("Showcases", "Care Companion", |
||||
|
"Healthcare onboarding with CarouselPage (3 pages), then a TabbedPage patient dashboard. Skip or complete onboarding to navigate to the dashboard via RemovePage.", |
||||
|
() => new CareCompanionAppPage()), |
||||
|
|
||||
|
// Carousel (ItemsControl) demos
|
||||
|
("Carousel", "Getting Started", |
||||
|
"Basic Carousel with image items and previous/next navigation buttons.", |
||||
|
() => new CarouselGettingStartedPage()), |
||||
|
("Carousel", "Transitions", |
||||
|
"Configure page transitions: PageSlide, CrossFade, 3D Rotation, or None.", |
||||
|
() => new CarouselTransitionsPage()), |
||||
|
("Carousel", "Customization", |
||||
|
"Adjust orientation and transition type to tailor the carousel layout.", |
||||
|
() => new CarouselCustomizationPage()), |
||||
|
("Carousel", "Gestures & Keyboard", |
||||
|
"Navigate items via swipe gesture and arrow keys. Toggle each input mode on and off.", |
||||
|
() => new CarouselGesturesPage()), |
||||
|
("Carousel", "Vertical Orientation", |
||||
|
"Carousel with Orientation set to Vertical, navigated with Up/Down keys, swipe, or buttons.", |
||||
|
() => new CarouselVerticalPage()), |
||||
|
("Carousel", "Multi-Item Peek", |
||||
|
"Adjust ViewportFraction to show multiple items simultaneously with adjacent cards peeking.", |
||||
|
() => new CarouselMultiItemPage()), |
||||
|
("Carousel", "Data Binding", |
||||
|
"Bind Carousel to an ObservableCollection and add, remove, or shuffle items at runtime.", |
||||
|
() => new CarouselDataBindingPage()), |
||||
|
("Carousel", "Curated Gallery", |
||||
|
"Editorial art gallery app with DrawerPage navigation, hero Carousel with PipsPager dots, and a horizontal peek carousel for collection highlights.", |
||||
|
() => new CarouselGalleryAppPage()), |
||||
|
}; |
||||
|
|
||||
|
public CarouselDemoPage() |
||||
|
{ |
||||
|
InitializeComponent(); |
||||
|
Loaded += OnLoaded; |
||||
|
} |
||||
|
|
||||
|
private async void OnLoaded(object? sender, RoutedEventArgs e) |
||||
|
{ |
||||
|
await SampleNav.PushAsync(NavigationDemoHelper.CreateGalleryHomePage(SampleNav, Demos), null); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,98 @@ |
|||||
|
<UserControl xmlns="https://github.com/avaloniaui" |
||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" |
||||
|
x:Class="ControlCatalog.Pages.CareCompanionAppPage"> |
||||
|
<UserControl.Styles> |
||||
|
<Style Selector="PipsPager /template/ ListBox ListBoxItem"> |
||||
|
<Setter Property="Width" Value="24" /> |
||||
|
<Setter Property="Height" Value="24" /> |
||||
|
<Setter Property="Padding" Value="0" /> |
||||
|
<Setter Property="Margin" Value="2,0" /> |
||||
|
<Setter Property="MinWidth" Value="0" /> |
||||
|
<Setter Property="MinHeight" Value="0" /> |
||||
|
<Setter Property="ClipToBounds" Value="False" /> |
||||
|
<Setter Property="VerticalAlignment" Value="Center" /> |
||||
|
<Setter Property="Template"> |
||||
|
<ControlTemplate> |
||||
|
<Grid Background="Transparent"> |
||||
|
<Border Name="Pip" |
||||
|
Width="6" Height="6" CornerRadius="3" |
||||
|
HorizontalAlignment="Center" VerticalAlignment="Center" |
||||
|
Background="#d1d5db"> |
||||
|
<Border.Transitions> |
||||
|
<Transitions> |
||||
|
<DoubleTransition Property="Width" Duration="0:0:0.2" Easing="CubicEaseOut" /> |
||||
|
<DoubleTransition Property="Height" Duration="0:0:0.2" Easing="CubicEaseOut" /> |
||||
|
<CornerRadiusTransition Property="CornerRadius" Duration="0:0:0.2" Easing="CubicEaseOut" /> |
||||
|
<BrushTransition Property="Background" Duration="0:0:0.2" /> |
||||
|
</Transitions> |
||||
|
</Border.Transitions> |
||||
|
</Border> |
||||
|
</Grid> |
||||
|
</ControlTemplate> |
||||
|
</Setter> |
||||
|
</Style> |
||||
|
<Style Selector="PipsPager /template/ ListBox ListBoxItem:pointerover /template/ Border#Pip"> |
||||
|
<Setter Property="Width" Value="8" /> |
||||
|
<Setter Property="Height" Value="8" /> |
||||
|
<Setter Property="CornerRadius" Value="4" /> |
||||
|
<Setter Property="Background" Value="#b0b0b0" /> |
||||
|
</Style> |
||||
|
<Style Selector="PipsPager /template/ ListBox ListBoxItem:selected /template/ Border#Pip"> |
||||
|
<Setter Property="Width" Value="20" /> |
||||
|
<Setter Property="Height" Value="6" /> |
||||
|
<Setter Property="CornerRadius" Value="3" /> |
||||
|
<Setter Property="Background" Value="#137fec" /> |
||||
|
</Style> |
||||
|
<Style Selector="PipsPager /template/ ListBox ListBoxItem:selected:pointerover /template/ Border#Pip"> |
||||
|
<Setter Property="Width" Value="20" /> |
||||
|
<Setter Property="Height" Value="6" /> |
||||
|
<Setter Property="CornerRadius" Value="3" /> |
||||
|
<Setter Property="Background" Value="#0a5bb5" /> |
||||
|
</Style> |
||||
|
<Style Selector="PipsPager /template/ ListBox ListBoxItem:pressed /template/ Border#Pip"> |
||||
|
<Setter Property="Width" Value="6" /> |
||||
|
<Setter Property="Height" Value="6" /> |
||||
|
<Setter Property="Background" Value="#909090" /> |
||||
|
</Style> |
||||
|
</UserControl.Styles> |
||||
|
<DockPanel> |
||||
|
<ScrollViewer x:Name="InfoPanel" DockPanel.Dock="Right" Width="300"> |
||||
|
<StackPanel Margin="16" Spacing="16"> |
||||
|
|
||||
|
<TextBlock Text="Care Companion" FontSize="16" FontWeight="SemiBold" |
||||
|
Foreground="{DynamicResource SystemControlHighlightAccentBrush}" /> |
||||
|
|
||||
|
<TextBlock TextWrapping="Wrap" FontSize="12" Opacity="0.7" |
||||
|
Text="A patient-focused healthcare companion app. CarouselPage handles onboarding (swipe or tap Next) with PipsPager as custom pill-shaped page indicators. Tapping Skip or Get Started pushes the TabbedPage dashboard and removes the onboarding from the navigation stack." /> |
||||
|
|
||||
|
<Separator /> |
||||
|
|
||||
|
<TextBlock Text="Navigation Flow" FontSize="13" FontWeight="SemiBold" /> |
||||
|
<StackPanel Spacing="4"> |
||||
|
<TextBlock FontSize="12" TextWrapping="Wrap" Text="1. CarouselPage is the NavigationPage root" /> |
||||
|
<TextBlock FontSize="12" TextWrapping="Wrap" Text="2. Swipe or tap Next to advance pages" /> |
||||
|
<TextBlock FontSize="12" TextWrapping="Wrap" Text="3. Skip jumps to Get Started page" /> |
||||
|
<TextBlock FontSize="12" TextWrapping="Wrap" Text="4. Get Started pushes TabbedPage dashboard" /> |
||||
|
<TextBlock FontSize="12" TextWrapping="Wrap" Text="5. RemovePage(carousel) cleans the stack" /> |
||||
|
</StackPanel> |
||||
|
|
||||
|
<Separator /> |
||||
|
|
||||
|
<TextBlock Text="Design" FontSize="13" FontWeight="SemiBold" /> |
||||
|
<StackPanel Spacing="4"> |
||||
|
<TextBlock FontSize="12" Text="Primary: #137fec (healthcare blue)" /> |
||||
|
<TextBlock FontSize="12" Text="Background: #f6f7f8 (off-white)" /> |
||||
|
<TextBlock FontSize="12" Text="Cards: #ffffff with border" /> |
||||
|
<TextBlock FontSize="12" Text="Success: #10b981 (streak/done)" /> |
||||
|
<TextBlock FontSize="12" Text="Roundness: 12-16px corners" /> |
||||
|
</StackPanel> |
||||
|
|
||||
|
</StackPanel> |
||||
|
</ScrollViewer> |
||||
|
|
||||
|
<Border BorderBrush="{DynamicResource SystemControlForegroundBaseMediumLowBrush}" |
||||
|
BorderThickness="1" CornerRadius="8" ClipToBounds="True"> |
||||
|
<NavigationPage x:Name="NavPage" /> |
||||
|
</Border> |
||||
|
</DockPanel> |
||||
|
</UserControl> |
||||
@ -0,0 +1,119 @@ |
|||||
|
<UserControl xmlns="https://github.com/avaloniaui" |
||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" |
||||
|
x:Class="ControlCatalog.Pages.CarouselCustomizationPage"> |
||||
|
<DockPanel> |
||||
|
<ScrollViewer DockPanel.Dock="Right" Width="260"> |
||||
|
<StackPanel Margin="12" Spacing="8"> |
||||
|
<TextBlock Text="Configuration" FontWeight="SemiBold" FontSize="16" |
||||
|
Foreground="{DynamicResource SystemControlHighlightAccentBrush}" /> |
||||
|
|
||||
|
<TextBlock Text="Navigation" FontWeight="SemiBold" FontSize="13" /> |
||||
|
|
||||
|
<Button x:Name="PreviousButton" |
||||
|
Content="Previous" |
||||
|
HorizontalAlignment="Stretch" /> |
||||
|
<Button x:Name="NextButton" |
||||
|
Content="Next" |
||||
|
HorizontalAlignment="Stretch" /> |
||||
|
|
||||
|
<Separator /> |
||||
|
|
||||
|
<TextBlock Text="Orientation" FontWeight="SemiBold" FontSize="13" /> |
||||
|
<ComboBox x:Name="OrientationCombo" |
||||
|
HorizontalAlignment="Stretch" |
||||
|
SelectedIndex="0"> |
||||
|
<ComboBoxItem>Horizontal</ComboBoxItem> |
||||
|
<ComboBoxItem>Vertical</ComboBoxItem> |
||||
|
</ComboBox> |
||||
|
|
||||
|
<TextBlock Text="Viewport Fraction" FontWeight="SemiBold" FontSize="13" /> |
||||
|
<Grid ColumnDefinitions="*,48" ColumnSpacing="8"> |
||||
|
<Slider x:Name="ViewportSlider" |
||||
|
Minimum="0.33" |
||||
|
Maximum="1.0" |
||||
|
Value="1.0" |
||||
|
TickFrequency="0.01" |
||||
|
HorizontalAlignment="Stretch" /> |
||||
|
<TextBlock x:Name="ViewportLabel" |
||||
|
Grid.Column="1" |
||||
|
Text="1.00" |
||||
|
VerticalAlignment="Center" |
||||
|
HorizontalAlignment="Right" |
||||
|
FontWeight="SemiBold" /> |
||||
|
</Grid> |
||||
|
<TextBlock x:Name="ViewportHint" |
||||
|
Text="1.00 shows a single full page." |
||||
|
FontSize="11" |
||||
|
Opacity="0.6" |
||||
|
TextWrapping="Wrap" /> |
||||
|
|
||||
|
<Separator /> |
||||
|
|
||||
|
<TextBlock Text="Options" FontWeight="SemiBold" FontSize="14" /> |
||||
|
|
||||
|
<CheckBox x:Name="WrapSelectionCheck" |
||||
|
Content="Wrap Selection" |
||||
|
IsChecked="False" |
||||
|
IsCheckedChanged="OnWrapSelectionChanged" /> |
||||
|
|
||||
|
<CheckBox x:Name="SwipeEnabledCheck" |
||||
|
Content="Swipe Enabled" |
||||
|
IsChecked="False" |
||||
|
IsCheckedChanged="OnSwipeEnabledChanged" /> |
||||
|
|
||||
|
<Separator /> |
||||
|
|
||||
|
<TextBlock Text="Status" FontWeight="SemiBold" FontSize="14" /> |
||||
|
<TextBlock x:Name="StatusText" |
||||
|
Text="Orientation: Horizontal" |
||||
|
Opacity="0.7" |
||||
|
TextWrapping="Wrap" /> |
||||
|
</StackPanel> |
||||
|
</ScrollViewer> |
||||
|
|
||||
|
<Border DockPanel.Dock="Right" Width="1" |
||||
|
Background="{DynamicResource SystemControlForegroundBaseMediumLowBrush}" /> |
||||
|
|
||||
|
<Border Margin="12" |
||||
|
BorderBrush="{DynamicResource SystemControlForegroundBaseMediumLowBrush}" |
||||
|
BorderThickness="1" |
||||
|
CornerRadius="6" |
||||
|
ClipToBounds="True"> |
||||
|
<Carousel x:Name="DemoCarousel" Height="300"> |
||||
|
<Carousel.PageTransition> |
||||
|
<PageSlide Duration="0.25" Orientation="Horizontal" /> |
||||
|
</Carousel.PageTransition> |
||||
|
|
||||
|
<Border Margin="14,12" CornerRadius="12" ClipToBounds="True"> |
||||
|
<Grid> |
||||
|
<Image Source="/Assets/delicate-arch-896885_640.jpg" Stretch="UniformToFill" /> |
||||
|
<Border Background="#80000000" VerticalAlignment="Bottom" Padding="12"> |
||||
|
<TextBlock Text="Item 1: Delicate Arch" Foreground="White" |
||||
|
HorizontalAlignment="Center" FontWeight="SemiBold" /> |
||||
|
</Border> |
||||
|
</Grid> |
||||
|
</Border> |
||||
|
|
||||
|
<Border Margin="14,12" CornerRadius="12" ClipToBounds="True"> |
||||
|
<Grid> |
||||
|
<Image Source="/Assets/hirsch-899118_640.jpg" Stretch="UniformToFill" /> |
||||
|
<Border Background="#80000000" VerticalAlignment="Bottom" Padding="12"> |
||||
|
<TextBlock Text="Item 2: Hirsch" Foreground="White" |
||||
|
HorizontalAlignment="Center" FontWeight="SemiBold" /> |
||||
|
</Border> |
||||
|
</Grid> |
||||
|
</Border> |
||||
|
|
||||
|
<Border Margin="14,12" CornerRadius="12" ClipToBounds="True"> |
||||
|
<Grid> |
||||
|
<Image Source="/Assets/maple-leaf-888807_640.jpg" Stretch="UniformToFill" /> |
||||
|
<Border Background="#80000000" VerticalAlignment="Bottom" Padding="12"> |
||||
|
<TextBlock Text="Item 3: Maple Leaf" Foreground="White" |
||||
|
HorizontalAlignment="Center" FontWeight="SemiBold" /> |
||||
|
</Border> |
||||
|
</Grid> |
||||
|
</Border> |
||||
|
</Carousel> |
||||
|
</Border> |
||||
|
</DockPanel> |
||||
|
</UserControl> |
||||
@ -0,0 +1,48 @@ |
|||||
|
using System; |
||||
|
using Avalonia.Animation; |
||||
|
using Avalonia.Controls; |
||||
|
using Avalonia.Controls.Primitives; |
||||
|
using Avalonia.Interactivity; |
||||
|
|
||||
|
namespace ControlCatalog.Pages |
||||
|
{ |
||||
|
public partial class CarouselCustomizationPage : UserControl |
||||
|
{ |
||||
|
public CarouselCustomizationPage() |
||||
|
{ |
||||
|
InitializeComponent(); |
||||
|
PreviousButton.Click += (_, _) => DemoCarousel.Previous(); |
||||
|
NextButton.Click += (_, _) => DemoCarousel.Next(); |
||||
|
OrientationCombo.SelectionChanged += (_, _) => ApplyOrientation(); |
||||
|
ViewportSlider.ValueChanged += OnViewportFractionChanged; |
||||
|
} |
||||
|
|
||||
|
private void ApplyOrientation() |
||||
|
{ |
||||
|
var horizontal = OrientationCombo.SelectedIndex == 0; |
||||
|
var axis = horizontal ? PageSlide.SlideAxis.Horizontal : PageSlide.SlideAxis.Vertical; |
||||
|
DemoCarousel.PageTransition = new PageSlide(TimeSpan.FromSeconds(0.25), axis); |
||||
|
StatusText.Text = $"Orientation: {(horizontal ? "Horizontal" : "Vertical")}"; |
||||
|
} |
||||
|
|
||||
|
private void OnViewportFractionChanged(object? sender, RangeBaseValueChangedEventArgs e) |
||||
|
{ |
||||
|
var value = Math.Round(e.NewValue, 2); |
||||
|
DemoCarousel.ViewportFraction = value; |
||||
|
ViewportLabel.Text = value.ToString("0.00"); |
||||
|
ViewportHint.Text = value >= 1d ? |
||||
|
"1.00 shows a single full page." : |
||||
|
$"{1d / value:0.##} pages fit in view. Try 0.80 for peeking."; |
||||
|
} |
||||
|
|
||||
|
private void OnWrapSelectionChanged(object? sender, RoutedEventArgs e) |
||||
|
{ |
||||
|
DemoCarousel.WrapSelection = WrapSelectionCheck.IsChecked == true; |
||||
|
} |
||||
|
|
||||
|
private void OnSwipeEnabledChanged(object? sender, RoutedEventArgs e) |
||||
|
{ |
||||
|
DemoCarousel.IsSwipeEnabled = SwipeEnabledCheck.IsChecked == true; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,60 @@ |
|||||
|
<UserControl xmlns="https://github.com/avaloniaui" |
||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" |
||||
|
xmlns:pages="clr-namespace:ControlCatalog.Pages" |
||||
|
x:Class="ControlCatalog.Pages.CarouselDataBindingPage"> |
||||
|
<DockPanel> |
||||
|
<ScrollViewer DockPanel.Dock="Right" Width="260"> |
||||
|
<StackPanel Margin="12" Spacing="8"> |
||||
|
<TextBlock Text="Collection" FontWeight="SemiBold" FontSize="16" |
||||
|
Foreground="{DynamicResource SystemControlHighlightAccentBrush}" /> |
||||
|
|
||||
|
<TextBlock Text="Navigation" FontWeight="SemiBold" FontSize="13" /> |
||||
|
<Button x:Name="PreviousButton" Content="Previous" HorizontalAlignment="Stretch" /> |
||||
|
<Button x:Name="NextButton" Content="Next" HorizontalAlignment="Stretch" /> |
||||
|
|
||||
|
<Separator /> |
||||
|
|
||||
|
<TextBlock Text="Modify Items" FontWeight="SemiBold" FontSize="13" /> |
||||
|
<TextBlock TextWrapping="Wrap" FontSize="11" Opacity="0.6" |
||||
|
Text="The Carousel is bound to an ObservableCollection. Changes reflect immediately." /> |
||||
|
<Button x:Name="AddButton" Content="Add Item" HorizontalAlignment="Stretch" /> |
||||
|
<Button x:Name="RemoveButton" Content="Remove Current" HorizontalAlignment="Stretch" /> |
||||
|
<Button x:Name="ShuffleButton" Content="Shuffle" HorizontalAlignment="Stretch" /> |
||||
|
|
||||
|
<Separator /> |
||||
|
|
||||
|
<TextBlock Text="Status" FontWeight="SemiBold" FontSize="14" /> |
||||
|
<TextBlock x:Name="StatusText" Text="Item: 1 / 4" |
||||
|
Opacity="0.7" TextWrapping="Wrap" /> |
||||
|
</StackPanel> |
||||
|
</ScrollViewer> |
||||
|
|
||||
|
<Border DockPanel.Dock="Right" Width="1" |
||||
|
Background="{DynamicResource SystemControlForegroundBaseMediumLowBrush}" /> |
||||
|
|
||||
|
<Border Margin="12" |
||||
|
BorderBrush="{DynamicResource SystemControlForegroundBaseMediumLowBrush}" |
||||
|
BorderThickness="1" CornerRadius="6" ClipToBounds="True"> |
||||
|
<Carousel x:Name="DemoCarousel" |
||||
|
Height="280" |
||||
|
IsSwipeEnabled="True"> |
||||
|
<Carousel.PageTransition> |
||||
|
<CrossFade Duration="0.3" /> |
||||
|
</Carousel.PageTransition> |
||||
|
<Carousel.ItemTemplate> |
||||
|
<DataTemplate x:DataType="pages:CarouselCardItem"> |
||||
|
<Border CornerRadius="14" Margin="14,12" ClipToBounds="True" |
||||
|
Background="{Binding Background}"> |
||||
|
<StackPanel VerticalAlignment="Center" HorizontalAlignment="Center" Spacing="8"> |
||||
|
<TextBlock Text="{Binding Number}" FontSize="52" FontWeight="Bold" |
||||
|
Foreground="White" HorizontalAlignment="Center" LetterSpacing="-2" /> |
||||
|
<TextBlock Text="{Binding Title}" FontSize="15" FontWeight="SemiBold" |
||||
|
Foreground="{Binding Accent}" HorizontalAlignment="Center" /> |
||||
|
</StackPanel> |
||||
|
</Border> |
||||
|
</DataTemplate> |
||||
|
</Carousel.ItemTemplate> |
||||
|
</Carousel> |
||||
|
</Border> |
||||
|
</DockPanel> |
||||
|
</UserControl> |
||||
@ -0,0 +1,95 @@ |
|||||
|
using System; |
||||
|
using System.Collections.ObjectModel; |
||||
|
using System.Linq; |
||||
|
using Avalonia.Controls; |
||||
|
using Avalonia.Interactivity; |
||||
|
using Avalonia.Media; |
||||
|
|
||||
|
namespace ControlCatalog.Pages |
||||
|
{ |
||||
|
public class CarouselCardItem |
||||
|
{ |
||||
|
public string Number { get; set; } = ""; |
||||
|
public string Title { get; set; } = ""; |
||||
|
public IBrush Background { get; set; } = Brushes.Gray; |
||||
|
public IBrush Accent { get; set; } = Brushes.White; |
||||
|
} |
||||
|
|
||||
|
public partial class CarouselDataBindingPage : UserControl |
||||
|
{ |
||||
|
private static readonly (string Title, string Color, string Accent)[] Palette = |
||||
|
{ |
||||
|
("Neon Pulse", "#3525CD", "#C3C0FF"), ("Ephemeral Blue", "#0891B2", "#BAF0FA"), |
||||
|
("Forest Forms", "#059669", "#A7F3D0"), ("Golden Hour", "#D97706", "#FDE68A"), |
||||
|
("Crimson Wave", "#BE185D", "#FBCFE8"), ("Stone Age", "#57534E", "#D6D3D1"), |
||||
|
}; |
||||
|
|
||||
|
private readonly ObservableCollection<CarouselCardItem> _items = new(); |
||||
|
private int _addCounter; |
||||
|
|
||||
|
public CarouselDataBindingPage() |
||||
|
{ |
||||
|
InitializeComponent(); |
||||
|
DemoCarousel.ItemsSource = _items; |
||||
|
DemoCarousel.SelectionChanged += OnSelectionChanged; |
||||
|
|
||||
|
for (var i = 0; i < 4; i++) |
||||
|
AppendItem(); |
||||
|
|
||||
|
PreviousButton.Click += (_, _) => DemoCarousel.Previous(); |
||||
|
NextButton.Click += (_, _) => DemoCarousel.Next(); |
||||
|
AddButton.Click += OnAddItem; |
||||
|
RemoveButton.Click += OnRemoveCurrent; |
||||
|
ShuffleButton.Click += OnShuffle; |
||||
|
UpdateStatus(); |
||||
|
} |
||||
|
|
||||
|
private void AppendItem() |
||||
|
{ |
||||
|
var (title, color, accent) = Palette[_addCounter % Palette.Length]; |
||||
|
_items.Add(new CarouselCardItem |
||||
|
{ |
||||
|
Number = $"{_items.Count + 1:D2}", |
||||
|
Title = title, |
||||
|
Background = new SolidColorBrush(Color.Parse(color)), |
||||
|
Accent = new SolidColorBrush(Color.Parse(accent)), |
||||
|
}); |
||||
|
_addCounter++; |
||||
|
} |
||||
|
|
||||
|
private void OnAddItem(object? sender, RoutedEventArgs e) |
||||
|
{ |
||||
|
AppendItem(); |
||||
|
UpdateStatus(); |
||||
|
} |
||||
|
|
||||
|
private void OnRemoveCurrent(object? sender, RoutedEventArgs e) |
||||
|
{ |
||||
|
if (_items.Count == 0) |
||||
|
return; |
||||
|
var idx = Math.Clamp(DemoCarousel.SelectedIndex, 0, _items.Count - 1); |
||||
|
_items.RemoveAt(idx); |
||||
|
UpdateStatus(); |
||||
|
} |
||||
|
|
||||
|
private void OnShuffle(object? sender, RoutedEventArgs e) |
||||
|
{ |
||||
|
var rng = new Random(); |
||||
|
var shuffled = _items.OrderBy(_ => rng.Next()).ToList(); |
||||
|
_items.Clear(); |
||||
|
foreach (var item in shuffled) |
||||
|
_items.Add(item); |
||||
|
UpdateStatus(); |
||||
|
} |
||||
|
|
||||
|
private void OnSelectionChanged(object? sender, SelectionChangedEventArgs e) |
||||
|
{ |
||||
|
UpdateStatus(); |
||||
|
} |
||||
|
|
||||
|
private void UpdateStatus() |
||||
|
{ |
||||
|
StatusText.Text = $"Item: {DemoCarousel.SelectedIndex + 1} / {_items.Count}"; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,557 @@ |
|||||
|
<UserControl xmlns="https://github.com/avaloniaui" |
||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" |
||||
|
x:Class="ControlCatalog.Pages.CarouselGalleryAppPage" |
||||
|
Background="#F8F9FB"> |
||||
|
<UserControl.Resources> |
||||
|
<!-- White pip colors for the hero dark background --> |
||||
|
<SolidColorBrush x:Key="PipsPagerSelectionIndicatorForeground" Color="#7FFFFFFF" /> |
||||
|
<SolidColorBrush x:Key="PipsPagerSelectionIndicatorForegroundPointerOver" Color="#BFFFFFFF" /> |
||||
|
<SolidColorBrush x:Key="PipsPagerSelectionIndicatorForegroundPressed" Color="#BFFFFFFF" /> |
||||
|
<SolidColorBrush x:Key="PipsPagerSelectionIndicatorForegroundSelected" Color="#FFFFFFFF" /> |
||||
|
<SolidColorBrush x:Key="PipsPagerSelectionIndicatorForegroundDisabled" Color="#3FFFFFFF" /> |
||||
|
<SolidColorBrush x:Key="PipsPagerNavigationButtonForeground" Color="#7FFFFFFF" /> |
||||
|
<SolidColorBrush x:Key="PipsPagerNavigationButtonForegroundPointerOver" Color="#BFFFFFFF" /> |
||||
|
<SolidColorBrush x:Key="PipsPagerNavigationButtonForegroundPressed" Color="#BFFFFFFF" /> |
||||
|
</UserControl.Resources> |
||||
|
|
||||
|
|
||||
|
<DockPanel> |
||||
|
|
||||
|
<!-- Right info panel — visible when width >= 640px --> |
||||
|
<ScrollViewer x:Name="InfoPanel" DockPanel.Dock="Right" Width="290" IsVisible="False"> |
||||
|
<StackPanel Margin="16" Spacing="16"> |
||||
|
|
||||
|
<TextBlock Text="Curated Gallery" FontSize="16" FontWeight="SemiBold" |
||||
|
Foreground="{DynamicResource SystemControlHighlightAccentBrush}" /> |
||||
|
|
||||
|
<TextBlock TextWrapping="Wrap" FontSize="12" Opacity="0.7" |
||||
|
Text="Art gallery editorial app showcasing a full-bleed hero Carousel synced with a pill-shaped PipsPager, a peek Collection Highlights scroll list, Curators' Choice cards, and a Join the Circle subscription section. Navigation via DrawerPage side menu." /> |
||||
|
|
||||
|
<Separator /> |
||||
|
|
||||
|
<TextBlock Text="Navigation Flow" FontSize="13" FontWeight="SemiBold" /> |
||||
|
<StackPanel Spacing="4"> |
||||
|
<TextBlock FontSize="12" TextWrapping="Wrap" Text="1. DrawerPage: root, side placement" /> |
||||
|
<TextBlock FontSize="12" TextWrapping="Wrap" Text="2. Hamburger overlaid on hero opens the drawer pane" /> |
||||
|
<TextBlock FontSize="12" TextWrapping="Wrap" Text="3. Hero: full-bleed Carousel + PipsPager (pill dots)" /> |
||||
|
<TextBlock FontSize="12" TextWrapping="Wrap" Text="4. PipsPager synced bidirectionally with Carousel" /> |
||||
|
<TextBlock FontSize="12" TextWrapping="Wrap" Text="5. Mouse drag on hero navigates carousel slides" /> |
||||
|
</StackPanel> |
||||
|
|
||||
|
<Separator /> |
||||
|
|
||||
|
<TextBlock Text="Key Code" FontSize="13" FontWeight="SemiBold" /> |
||||
|
<Border Background="{DynamicResource SystemControlBackgroundBaseLowBrush}" |
||||
|
CornerRadius="4" Padding="8"> |
||||
|
<TextBlock FontFamily="Cascadia Code,Consolas,Menlo,monospace" |
||||
|
FontSize="10" TextWrapping="Wrap" |
||||
|
Text="HeroCarousel.SelectionChanged
 += OnHeroSelectionChanged;
HeroPager.SelectedIndexChanged
 += OnPagerIndexChanged;

// Bidirectional sync guard
if (_syncing) return;
_syncing = true;
HeroPager.SelectedPageIndex
 = HeroCarousel.SelectedIndex;
_syncing = false;" /> |
||||
|
</Border> |
||||
|
|
||||
|
</StackPanel> |
||||
|
</ScrollViewer> |
||||
|
|
||||
|
<Border BorderBrush="{DynamicResource SystemControlForegroundBaseMediumLowBrush}" |
||||
|
BorderThickness="1" CornerRadius="8" ClipToBounds="True"> |
||||
|
|
||||
|
<DrawerPage x:Name="RootDrawer" |
||||
|
DrawerLength="260" |
||||
|
IsGestureEnabled="True"> |
||||
|
<DrawerPage.Styles> |
||||
|
<!-- Hide the DrawerPage built-in top bar so only our custom hero overlay bar is shown --> |
||||
|
<Style Selector="DrawerPage#RootDrawer /template/ Border#PART_TopBar"> |
||||
|
<Setter Property="IsVisible" Value="False" /> |
||||
|
</Style> |
||||
|
</DrawerPage.Styles> |
||||
|
|
||||
|
<!-- Drawer header --> |
||||
|
<DrawerPage.DrawerHeader> |
||||
|
<Border Background="#3525CD" Padding="20,32,20,20"> |
||||
|
<StackPanel Spacing="4"> |
||||
|
<TextBlock Text="CURATED" |
||||
|
FontSize="20" |
||||
|
FontWeight="Bold" |
||||
|
Foreground="White" |
||||
|
LetterSpacing="-0.4" /> |
||||
|
<TextBlock Text="The Digital Gallery" |
||||
|
FontSize="12" |
||||
|
Foreground="#C3C0FF" |
||||
|
Opacity="0.85" /> |
||||
|
</StackPanel> |
||||
|
</Border> |
||||
|
</DrawerPage.DrawerHeader> |
||||
|
|
||||
|
<!-- Drawer menu --> |
||||
|
<DrawerPage.Drawer> |
||||
|
<StackPanel Background="#F8F9FB"> |
||||
|
<ListBox x:Name="DrawerMenu" |
||||
|
Background="Transparent" |
||||
|
SelectionChanged="OnDrawerMenuSelectionChanged"> |
||||
|
<ListBoxItem Padding="20,14"> |
||||
|
<StackPanel Orientation="Horizontal" Spacing="16"> |
||||
|
<Path Data="M10 20v-6h4v6h5v-8h3L12 3 2 12h3v8z" |
||||
|
Fill="#3525CD" Width="20" Height="20" Stretch="Uniform" /> |
||||
|
<TextBlock Text="Discover" FontSize="15" FontWeight="SemiBold" |
||||
|
Foreground="#191C1E" VerticalAlignment="Center" /> |
||||
|
</StackPanel> |
||||
|
</ListBoxItem> |
||||
|
<ListBoxItem Padding="20,14"> |
||||
|
<StackPanel Orientation="Horizontal" Spacing="16"> |
||||
|
<Path Data="M4 6h16v2H4zm0 5h16v2H4zm0 5h16v2H4z" |
||||
|
Fill="#464555" Width="20" Height="20" Stretch="Uniform" /> |
||||
|
<TextBlock Text="Collection" FontSize="15" |
||||
|
Foreground="#464555" VerticalAlignment="Center" /> |
||||
|
</StackPanel> |
||||
|
</ListBoxItem> |
||||
|
<ListBoxItem Padding="20,14"> |
||||
|
<StackPanel Orientation="Horizontal" Spacing="16"> |
||||
|
<Path Data="M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm-7 14l-5-5 1.41-1.41L12 14.17l7.59-7.59L21 8l-9 9z" |
||||
|
Fill="#464555" Width="20" Height="20" Stretch="Uniform" /> |
||||
|
<TextBlock Text="Archive" FontSize="15" |
||||
|
Foreground="#464555" VerticalAlignment="Center" /> |
||||
|
</StackPanel> |
||||
|
</ListBoxItem> |
||||
|
<ListBoxItem Padding="20,14"> |
||||
|
<StackPanel Orientation="Horizontal" Spacing="16"> |
||||
|
<Path Data="M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z" |
||||
|
Fill="#464555" Width="20" Height="20" Stretch="Uniform" /> |
||||
|
<TextBlock Text="Profile" FontSize="15" |
||||
|
Foreground="#464555" VerticalAlignment="Center" /> |
||||
|
</StackPanel> |
||||
|
</ListBoxItem> |
||||
|
</ListBox> |
||||
|
|
||||
|
<Separator Margin="20,8" /> |
||||
|
|
||||
|
<StackPanel Margin="20,8" Spacing="0"> |
||||
|
<TextBlock Text="EXHIBITIONS" |
||||
|
FontSize="11" |
||||
|
FontWeight="Bold" |
||||
|
Foreground="#777587" |
||||
|
LetterSpacing="1.2" |
||||
|
Margin="0,0,0,16" /> |
||||
|
|
||||
|
<Grid ColumnDefinitions="4,*" Margin="0,0,0,14"> |
||||
|
<Border Grid.Column="0" Width="4" Height="38" |
||||
|
CornerRadius="2" Background="#3525CD" |
||||
|
VerticalAlignment="Center" Margin="0,0,14,0" /> |
||||
|
<StackPanel Grid.Column="1" Spacing="2" VerticalAlignment="Center"> |
||||
|
<TextBlock Text="Neon Pulse" FontSize="14" FontWeight="SemiBold" |
||||
|
Foreground="#191C1E" /> |
||||
|
<TextBlock Text="Opens March 20" FontSize="11" Foreground="#777587" /> |
||||
|
</StackPanel> |
||||
|
</Grid> |
||||
|
|
||||
|
<Grid ColumnDefinitions="4,*" Margin="0,0,0,14"> |
||||
|
<Border Grid.Column="0" Width="4" Height="38" |
||||
|
CornerRadius="2" Background="#4F46E5" |
||||
|
VerticalAlignment="Center" Margin="0,0,14,0" /> |
||||
|
<StackPanel Grid.Column="1" Spacing="2" VerticalAlignment="Center"> |
||||
|
<TextBlock Text="Fragmented Forms" FontSize="14" FontWeight="SemiBold" |
||||
|
Foreground="#191C1E" /> |
||||
|
<TextBlock Text="Now Open" FontSize="11" Foreground="#4F46E5" /> |
||||
|
</StackPanel> |
||||
|
</Grid> |
||||
|
|
||||
|
<Grid ColumnDefinitions="4,*"> |
||||
|
<Border Grid.Column="0" Width="4" Height="38" |
||||
|
CornerRadius="2" Background="#B84B00" |
||||
|
VerticalAlignment="Center" Margin="0,0,14,0" /> |
||||
|
<StackPanel Grid.Column="1" Spacing="2" VerticalAlignment="Center"> |
||||
|
<TextBlock Text="The Digital Horizon" FontSize="14" FontWeight="SemiBold" |
||||
|
Foreground="#191C1E" /> |
||||
|
<TextBlock Text="Closing Soon" FontSize="11" Foreground="#B84B00" /> |
||||
|
</StackPanel> |
||||
|
</Grid> |
||||
|
</StackPanel> |
||||
|
</StackPanel> |
||||
|
</DrawerPage.Drawer> |
||||
|
|
||||
|
<!-- Main content: hero carousel IS the header --> |
||||
|
<DrawerPage.Content> |
||||
|
<Grid RowDefinitions="Auto,*"> |
||||
|
|
||||
|
<!-- Row 0: Hero carousel header — also handles mouse drag for swipe navigation --> |
||||
|
<Grid Height="320" |
||||
|
PointerPressed="OnHeroPointerPressed" |
||||
|
PointerReleased="OnHeroPointerReleased" |
||||
|
PointerCaptureLost="OnHeroPointerCaptureLost"> |
||||
|
|
||||
|
<!-- Full-bleed hero carousel --> |
||||
|
<Carousel x:Name="HeroCarousel" |
||||
|
IsSwipeEnabled="True"> |
||||
|
<Carousel.PageTransition> |
||||
|
<PageSlide Duration="0.35" Orientation="Horizontal" /> |
||||
|
</Carousel.PageTransition> |
||||
|
|
||||
|
<!-- Hero 1 --> |
||||
|
<Grid> |
||||
|
<Image Source="/Assets/ModernApp/gallery_city.jpg" Stretch="UniformToFill" /> |
||||
|
<Border> |
||||
|
<Border.Background> |
||||
|
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1"> |
||||
|
<GradientStop Color="#88000000" Offset="0" /> |
||||
|
<GradientStop Color="#00000000" Offset="0.35" /> |
||||
|
<GradientStop Color="#00000000" Offset="0.55" /> |
||||
|
<GradientStop Color="#CC000000" Offset="1" /> |
||||
|
</LinearGradientBrush> |
||||
|
</Border.Background> |
||||
|
</Border> |
||||
|
<StackPanel VerticalAlignment="Bottom" Margin="20,0,20,44" Spacing="4"> |
||||
|
<TextBlock Text="FEATURED EXHIBITION" |
||||
|
FontSize="11" FontWeight="Bold" |
||||
|
Foreground="#C3C0FF" LetterSpacing="1.5" /> |
||||
|
<TextBlock Text="Neon Pulse: The New Abstract" |
||||
|
FontSize="22" FontWeight="Bold" |
||||
|
Foreground="White" TextWrapping="Wrap" LetterSpacing="-0.4" /> |
||||
|
</StackPanel> |
||||
|
</Grid> |
||||
|
|
||||
|
<!-- Hero 2 --> |
||||
|
<Grid> |
||||
|
<Image Source="/Assets/ModernApp/gallery_alpine.jpg" Stretch="UniformToFill" /> |
||||
|
<Border> |
||||
|
<Border.Background> |
||||
|
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1"> |
||||
|
<GradientStop Color="#88000000" Offset="0" /> |
||||
|
<GradientStop Color="#00000000" Offset="0.35" /> |
||||
|
<GradientStop Color="#00000000" Offset="0.55" /> |
||||
|
<GradientStop Color="#CC000000" Offset="1" /> |
||||
|
</LinearGradientBrush> |
||||
|
</Border.Background> |
||||
|
</Border> |
||||
|
<StackPanel VerticalAlignment="Bottom" Margin="20,0,20,44" Spacing="4"> |
||||
|
<TextBlock Text="NOW OPEN" |
||||
|
FontSize="11" FontWeight="Bold" |
||||
|
Foreground="#C3C0FF" LetterSpacing="1.5" /> |
||||
|
<TextBlock Text="Fragmented Forms: Sculpture Today" |
||||
|
FontSize="22" FontWeight="Bold" |
||||
|
Foreground="White" TextWrapping="Wrap" LetterSpacing="-0.4" /> |
||||
|
</StackPanel> |
||||
|
</Grid> |
||||
|
|
||||
|
<!-- Hero 3 --> |
||||
|
<Grid> |
||||
|
<Image Source="/Assets/ModernApp/gallery_venice.jpg" Stretch="UniformToFill" /> |
||||
|
<Border> |
||||
|
<Border.Background> |
||||
|
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1"> |
||||
|
<GradientStop Color="#88000000" Offset="0" /> |
||||
|
<GradientStop Color="#00000000" Offset="0.35" /> |
||||
|
<GradientStop Color="#00000000" Offset="0.55" /> |
||||
|
<GradientStop Color="#CC000000" Offset="1" /> |
||||
|
</LinearGradientBrush> |
||||
|
</Border.Background> |
||||
|
</Border> |
||||
|
<StackPanel VerticalAlignment="Bottom" Margin="20,0,20,44" Spacing="4"> |
||||
|
<TextBlock Text="CLOSING SOON" |
||||
|
FontSize="11" FontWeight="Bold" |
||||
|
Foreground="#FFCDD2" LetterSpacing="1.5" /> |
||||
|
<TextBlock Text="The Digital Horizon: Web3 & Generative Art" |
||||
|
FontSize="22" FontWeight="Bold" |
||||
|
Foreground="White" TextWrapping="Wrap" LetterSpacing="-0.4" /> |
||||
|
</StackPanel> |
||||
|
</Grid> |
||||
|
</Carousel> |
||||
|
|
||||
|
<!-- PipsPager overlaid near bottom of hero — pill-shaped, no nav arrows --> |
||||
|
<PipsPager x:Name="HeroPager" |
||||
|
NumberOfPages="3" |
||||
|
IsPreviousButtonVisible="False" |
||||
|
IsNextButtonVisible="False" |
||||
|
HorizontalAlignment="Center" |
||||
|
VerticalAlignment="Bottom" |
||||
|
Margin="0,0,0,18"> |
||||
|
<PipsPager.Styles> |
||||
|
<Style Selector="PipsPager /template/ ListBox ListBoxItem"> |
||||
|
<Setter Property="Width" Value="24" /> |
||||
|
<Setter Property="Height" Value="24" /> |
||||
|
<Setter Property="Padding" Value="0" /> |
||||
|
<Setter Property="Margin" Value="2,0" /> |
||||
|
<Setter Property="MinWidth" Value="0" /> |
||||
|
<Setter Property="MinHeight" Value="0" /> |
||||
|
<Setter Property="ClipToBounds" Value="False" /> |
||||
|
<Setter Property="VerticalAlignment" Value="Center" /> |
||||
|
<Setter Property="Template"> |
||||
|
<ControlTemplate> |
||||
|
<Grid Background="Transparent"> |
||||
|
<Border Name="Pip" |
||||
|
Width="6" Height="6" CornerRadius="3" |
||||
|
HorizontalAlignment="Center" VerticalAlignment="Center" |
||||
|
Background="#7FFFFFFF"> |
||||
|
<Border.Transitions> |
||||
|
<Transitions> |
||||
|
<DoubleTransition Property="Width" Duration="0:0:0.2" Easing="CubicEaseOut" /> |
||||
|
<CornerRadiusTransition Property="CornerRadius" Duration="0:0:0.2" Easing="CubicEaseOut" /> |
||||
|
<BrushTransition Property="Background" Duration="0:0:0.2" /> |
||||
|
</Transitions> |
||||
|
</Border.Transitions> |
||||
|
</Border> |
||||
|
</Grid> |
||||
|
</ControlTemplate> |
||||
|
</Setter> |
||||
|
</Style> |
||||
|
<Style Selector="PipsPager /template/ ListBox ListBoxItem:pointerover /template/ Border#Pip"> |
||||
|
<Setter Property="Width" Value="8" /> |
||||
|
<Setter Property="Height" Value="8" /> |
||||
|
<Setter Property="CornerRadius" Value="4" /> |
||||
|
<Setter Property="Background" Value="#BFFFFFFF" /> |
||||
|
</Style> |
||||
|
<Style Selector="PipsPager /template/ ListBox ListBoxItem:selected /template/ Border#Pip"> |
||||
|
<Setter Property="Width" Value="22" /> |
||||
|
<Setter Property="Height" Value="6" /> |
||||
|
<Setter Property="CornerRadius" Value="3" /> |
||||
|
<Setter Property="Background" Value="#FFFFFFFF" /> |
||||
|
</Style> |
||||
|
<Style Selector="PipsPager /template/ ListBox ListBoxItem:selected:pointerover /template/ Border#Pip"> |
||||
|
<Setter Property="Width" Value="22" /> |
||||
|
<Setter Property="Height" Value="6" /> |
||||
|
<Setter Property="CornerRadius" Value="3" /> |
||||
|
<Setter Property="Background" Value="#E8FFFFFF" /> |
||||
|
</Style> |
||||
|
</PipsPager.Styles> |
||||
|
</PipsPager> |
||||
|
|
||||
|
<!-- Top bar overlaid on hero --> |
||||
|
<Grid ColumnDefinitions="Auto,*,Auto" |
||||
|
VerticalAlignment="Top" |
||||
|
Margin="4,8,4,0"> |
||||
|
<Button Grid.Column="0" |
||||
|
Background="Transparent" |
||||
|
BorderThickness="0" |
||||
|
Padding="12,8" |
||||
|
Click="OnHamburgerClick"> |
||||
|
<Path Data="M3 18h18v-2H3v2zm0-5h18v-2H3v2zm0-7v2h18V6H3z" |
||||
|
Fill="White" Width="22" Height="22" Stretch="Uniform" /> |
||||
|
</Button> |
||||
|
<TextBlock Grid.Column="1" |
||||
|
Text="Curated" |
||||
|
FontSize="18" |
||||
|
FontWeight="Bold" |
||||
|
Foreground="White" |
||||
|
VerticalAlignment="Center" |
||||
|
HorizontalAlignment="Center" |
||||
|
LetterSpacing="-0.3" /> |
||||
|
<Button Grid.Column="2" |
||||
|
Background="Transparent" |
||||
|
BorderThickness="0" |
||||
|
Padding="12,8"> |
||||
|
<Path Data="M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z" |
||||
|
Fill="White" Width="22" Height="22" Stretch="Uniform" /> |
||||
|
</Button> |
||||
|
</Grid> |
||||
|
|
||||
|
</Grid> |
||||
|
|
||||
|
<!-- Row 1: Scrollable body --> |
||||
|
<ScrollViewer Grid.Row="1" |
||||
|
VerticalScrollBarVisibility="Auto" |
||||
|
HorizontalScrollBarVisibility="Disabled"> |
||||
|
<StackPanel> |
||||
|
|
||||
|
<!-- Collection Highlights --> |
||||
|
<StackPanel Margin="0,28,0,0"> |
||||
|
<Grid ColumnDefinitions="*,Auto" Margin="20,0,20,16"> |
||||
|
<TextBlock Text="Collection Highlights" |
||||
|
FontSize="18" FontWeight="Bold" |
||||
|
Foreground="#191C1E" LetterSpacing="-0.3" /> |
||||
|
<TextBlock Grid.Column="1" |
||||
|
Text="SEE ALL" |
||||
|
FontSize="12" FontWeight="Bold" |
||||
|
Foreground="#3525CD" LetterSpacing="0.8" |
||||
|
VerticalAlignment="Center" /> |
||||
|
</Grid> |
||||
|
|
||||
|
<ScrollViewer HorizontalScrollBarVisibility="Hidden" |
||||
|
VerticalScrollBarVisibility="Disabled" |
||||
|
Margin="20,0,0,0"> |
||||
|
<StackPanel Orientation="Horizontal" Spacing="10"> |
||||
|
|
||||
|
<Border Width="180" Height="210" CornerRadius="12" ClipToBounds="True"> |
||||
|
<Grid> |
||||
|
<Image Source="/Assets/ModernApp/gallery_paris.jpg" Stretch="UniformToFill" /> |
||||
|
<Border Background="#80000000" VerticalAlignment="Bottom" Padding="12,10"> |
||||
|
<StackPanel Spacing="2"> |
||||
|
<TextBlock Text="SCULPTURE" FontSize="10" FontWeight="Bold" |
||||
|
Foreground="#C3C0FF" LetterSpacing="1" /> |
||||
|
<TextBlock Text="Fragmented Grace" FontSize="13" |
||||
|
FontWeight="SemiBold" Foreground="White" /> |
||||
|
</StackPanel> |
||||
|
</Border> |
||||
|
</Grid> |
||||
|
</Border> |
||||
|
|
||||
|
<Border Width="180" Height="210" CornerRadius="12" ClipToBounds="True"> |
||||
|
<Grid> |
||||
|
<Image Source="/Assets/ModernApp/gallery_bay.jpg" Stretch="UniformToFill" /> |
||||
|
<Border Background="#80000000" VerticalAlignment="Bottom" Padding="12,10"> |
||||
|
<StackPanel Spacing="2"> |
||||
|
<TextBlock Text="OIL PAINTING" FontSize="10" FontWeight="Bold" |
||||
|
Foreground="#C3C0FF" LetterSpacing="1" /> |
||||
|
<TextBlock Text="Ephemeral Blue" FontSize="13" |
||||
|
FontWeight="SemiBold" Foreground="White" /> |
||||
|
</StackPanel> |
||||
|
</Border> |
||||
|
</Grid> |
||||
|
</Border> |
||||
|
|
||||
|
<Border Width="180" Height="210" CornerRadius="12" ClipToBounds="True"> |
||||
|
<Grid> |
||||
|
<Image Source="/Assets/ModernApp/gallery_tropical.jpg" Stretch="UniformToFill" /> |
||||
|
<Border Background="#80000000" VerticalAlignment="Bottom" Padding="12,10"> |
||||
|
<StackPanel Spacing="2"> |
||||
|
<TextBlock Text="TEXTILE" FontSize="10" FontWeight="Bold" |
||||
|
Foreground="#C3C0FF" LetterSpacing="1" /> |
||||
|
<TextBlock Text="Interwoven Lines" FontSize="13" |
||||
|
FontWeight="SemiBold" Foreground="White" /> |
||||
|
</StackPanel> |
||||
|
</Border> |
||||
|
</Grid> |
||||
|
</Border> |
||||
|
|
||||
|
<Border Width="180" Height="210" CornerRadius="12" ClipToBounds="True"> |
||||
|
<Grid> |
||||
|
<Image Source="/Assets/ModernApp/gallery_alpine.jpg" Stretch="UniformToFill" /> |
||||
|
<Border Background="#80000000" VerticalAlignment="Bottom" Padding="12,10"> |
||||
|
<StackPanel Spacing="2"> |
||||
|
<TextBlock Text="PHOTOGRAPHY" FontSize="10" FontWeight="Bold" |
||||
|
Foreground="#C3C0FF" LetterSpacing="1" /> |
||||
|
<TextBlock Text="Silent Mountains" FontSize="13" |
||||
|
FontWeight="SemiBold" Foreground="White" /> |
||||
|
</StackPanel> |
||||
|
</Border> |
||||
|
</Grid> |
||||
|
</Border> |
||||
|
|
||||
|
<!-- Padding card to reveal peek of last item --> |
||||
|
<Border Width="20" Height="210" /> |
||||
|
|
||||
|
</StackPanel> |
||||
|
</ScrollViewer> |
||||
|
</StackPanel> |
||||
|
|
||||
|
<!-- Curators' Choice --> |
||||
|
<StackPanel Margin="20,32,20,0" Spacing="12"> |
||||
|
<TextBlock Text="Curators' Choice" |
||||
|
FontSize="20" FontWeight="Bold" |
||||
|
Foreground="#191C1E" HorizontalAlignment="Center" |
||||
|
LetterSpacing="-0.3" /> |
||||
|
<TextBlock Text="Hand-picked selections from our global network of artists." |
||||
|
FontSize="13" Foreground="#777587" |
||||
|
HorizontalAlignment="Center" TextAlignment="Center" |
||||
|
TextWrapping="Wrap" Margin="0,0,0,8" /> |
||||
|
|
||||
|
<!-- Two-column layout: large card left, two stacked badge cards right --> |
||||
|
<Grid ColumnDefinitions="*,130"> |
||||
|
|
||||
|
<!-- Left: main feature card --> |
||||
|
<Border Grid.Column="0" Background="White" CornerRadius="16" |
||||
|
Padding="20" Margin="0,0,10,0" |
||||
|
BoxShadow="0 2 16 0 #12191C1E"> |
||||
|
<StackPanel Spacing="10"> |
||||
|
<Path Data="M11.48 3.499a.562.562 0 0 1 1.04 0l2.125 5.111a.563.563 0 0 0 .475.345l5.518.442c.499.04.701.663.321.988l-4.204 3.602a.563.563 0 0 0-.182.557l1.285 5.385a.562.562 0 0 1-.84.61l-4.725-2.885a.562.562 0 0 0-.586 0L6.982 20.54a.562.562 0 0 1-.84-.61l1.285-5.386a.562.562 0 0 0-.182-.557l-4.204-3.602a.562.562 0 0 1 .321-.988l5.518-.442a.563.563 0 0 0 .475-.345L11.48 3.5z" |
||||
|
Fill="#3525CD" Width="22" Height="22" Stretch="Uniform" |
||||
|
HorizontalAlignment="Left" /> |
||||
|
<TextBlock Text="The Digital Horizon" |
||||
|
FontSize="17" FontWeight="Bold" |
||||
|
Foreground="#191C1E" TextWrapping="Wrap" /> |
||||
|
<TextBlock Text="Exploring Web3 and Generative Art" |
||||
|
FontSize="13" Foreground="#777587" TextWrapping="Wrap" /> |
||||
|
<Button Content="EXPLORE" |
||||
|
Margin="0,10,0,0" Padding="20,11" |
||||
|
FontSize="11" FontWeight="Bold" LetterSpacing="0.8" |
||||
|
CornerRadius="22" Foreground="White" HorizontalAlignment="Left"> |
||||
|
<Button.Background> |
||||
|
<LinearGradientBrush StartPoint="0,0" EndPoint="1,0"> |
||||
|
<GradientStop Color="#3525CD" Offset="0" /> |
||||
|
<GradientStop Color="#4F46E5" Offset="1" /> |
||||
|
</LinearGradientBrush> |
||||
|
</Button.Background> |
||||
|
</Button> |
||||
|
</StackPanel> |
||||
|
</Border> |
||||
|
|
||||
|
<!-- Right: two stacked badge cards --> |
||||
|
<StackPanel Grid.Column="1" Spacing="10"> |
||||
|
|
||||
|
<Border Background="White" CornerRadius="16" |
||||
|
BoxShadow="0 2 16 0 #12191C1E" |
||||
|
Padding="12"> |
||||
|
<StackPanel VerticalAlignment="Center" HorizontalAlignment="Center" |
||||
|
Spacing="8" Margin="0,12"> |
||||
|
<Path Data="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-1 14H9V8h2v8zm4 0h-2V8h2v8z" |
||||
|
Fill="#B84B00" Width="28" Height="28" Stretch="Uniform" |
||||
|
HorizontalAlignment="Center" /> |
||||
|
<TextBlock Text="TRENDING" |
||||
|
FontSize="10" FontWeight="Bold" |
||||
|
Foreground="#B84B00" LetterSpacing="1" |
||||
|
HorizontalAlignment="Center" /> |
||||
|
</StackPanel> |
||||
|
</Border> |
||||
|
|
||||
|
<Border Background="#EDEEF0" CornerRadius="16" Padding="12"> |
||||
|
<StackPanel VerticalAlignment="Center" HorizontalAlignment="Center" |
||||
|
Spacing="8" Margin="0,12"> |
||||
|
<Path Data="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-1.41 14.06L6.17 11.64l1.42-1.41 2.99 3 6.01-6.01 1.42 1.41-7.42 7.43z" |
||||
|
Fill="#464555" Width="28" Height="28" Stretch="Uniform" |
||||
|
HorizontalAlignment="Center" /> |
||||
|
<TextBlock Text="VERIFIED" |
||||
|
FontSize="10" FontWeight="Bold" |
||||
|
Foreground="#464555" LetterSpacing="1" |
||||
|
HorizontalAlignment="Center" /> |
||||
|
</StackPanel> |
||||
|
</Border> |
||||
|
|
||||
|
</StackPanel> |
||||
|
</Grid> |
||||
|
</StackPanel> |
||||
|
|
||||
|
<!-- Join the Circle --> |
||||
|
<Border Margin="20,32,20,32" CornerRadius="20" Padding="24" ClipToBounds="True"> |
||||
|
<Border.Background> |
||||
|
<LinearGradientBrush StartPoint="0,0" EndPoint="1,1"> |
||||
|
<GradientStop Color="#3525CD" Offset="0" /> |
||||
|
<GradientStop Color="#4F46E5" Offset="1" /> |
||||
|
</LinearGradientBrush> |
||||
|
</Border.Background> |
||||
|
<StackPanel Spacing="10"> |
||||
|
<TextBlock Text="Join the Circle" |
||||
|
FontSize="20" FontWeight="Bold" |
||||
|
Foreground="White" LetterSpacing="-0.3" /> |
||||
|
<TextBlock Text="Receive exclusive invitations to private viewings and new drop alerts." |
||||
|
FontSize="13" Foreground="#C3C0FF" |
||||
|
TextWrapping="Wrap" Opacity="0.9" LineHeight="20" /> |
||||
|
<TextBox PlaceholderText="Your email address" |
||||
|
Margin="0,6,0,0" |
||||
|
CornerRadius="12" |
||||
|
BorderThickness="1" |
||||
|
Padding="14,12" |
||||
|
Foreground="White" |
||||
|
PlaceholderForeground="#9896D8"> |
||||
|
<TextBox.Resources> |
||||
|
<SolidColorBrush x:Key="TextControlBackground" Color="#3C38B5" /> |
||||
|
<SolidColorBrush x:Key="TextControlBackgroundPointerOver" Color="#4440BE" /> |
||||
|
<SolidColorBrush x:Key="TextControlBackgroundFocused" Color="#3C38B5" /> |
||||
|
<SolidColorBrush x:Key="TextControlBorderBrush" Color="#5552C8" /> |
||||
|
<SolidColorBrush x:Key="TextControlBorderBrushPointerOver" Color="#7370D8" /> |
||||
|
<SolidColorBrush x:Key="TextControlBorderBrushFocused" Color="#8B88E8" /> |
||||
|
</TextBox.Resources> |
||||
|
</TextBox> |
||||
|
<Button Content="SUBSCRIBE" |
||||
|
Margin="0,2,0,0" Padding="24,12" |
||||
|
FontSize="12" FontWeight="Bold" LetterSpacing="1" |
||||
|
CornerRadius="24" Foreground="#3525CD" Background="White" |
||||
|
HorizontalAlignment="Left" /> |
||||
|
</StackPanel> |
||||
|
</Border> |
||||
|
|
||||
|
</StackPanel> |
||||
|
</ScrollViewer> |
||||
|
|
||||
|
</Grid> |
||||
|
</DrawerPage.Content> |
||||
|
</DrawerPage> |
||||
|
|
||||
|
</Border> |
||||
|
</DockPanel> |
||||
|
</UserControl> |
||||
@ -0,0 +1,101 @@ |
|||||
|
using System; |
||||
|
using Avalonia; |
||||
|
using Avalonia.Controls; |
||||
|
using Avalonia.Input; |
||||
|
using Avalonia.Interactivity; |
||||
|
|
||||
|
namespace ControlCatalog.Pages |
||||
|
{ |
||||
|
public partial class CarouselGalleryAppPage : UserControl |
||||
|
{ |
||||
|
private bool _syncing; |
||||
|
private Point _dragStart; |
||||
|
private bool _isDragging; |
||||
|
private const double SwipeThreshold = 50; |
||||
|
|
||||
|
private ScrollViewer? _infoPanel; |
||||
|
|
||||
|
public CarouselGalleryAppPage() |
||||
|
{ |
||||
|
InitializeComponent(); |
||||
|
_infoPanel = this.FindControl<ScrollViewer>("InfoPanel"); |
||||
|
HeroCarousel.SelectionChanged += OnHeroSelectionChanged; |
||||
|
HeroPager.SelectedIndexChanged += OnPagerIndexChanged; |
||||
|
} |
||||
|
|
||||
|
protected override void OnLoaded(RoutedEventArgs e) |
||||
|
{ |
||||
|
base.OnLoaded(e); |
||||
|
UpdateInfoPanelVisibility(); |
||||
|
} |
||||
|
|
||||
|
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) |
||||
|
{ |
||||
|
base.OnPropertyChanged(change); |
||||
|
if (change.Property == BoundsProperty) |
||||
|
UpdateInfoPanelVisibility(); |
||||
|
} |
||||
|
|
||||
|
private void UpdateInfoPanelVisibility() |
||||
|
{ |
||||
|
if (_infoPanel != null) |
||||
|
_infoPanel.IsVisible = Bounds.Width >= 640; |
||||
|
} |
||||
|
|
||||
|
private void OnHamburgerClick(object? sender, RoutedEventArgs e) |
||||
|
{ |
||||
|
RootDrawer.IsOpen = !RootDrawer.IsOpen; |
||||
|
} |
||||
|
|
||||
|
private void OnHeroSelectionChanged(object? sender, SelectionChangedEventArgs e) |
||||
|
{ |
||||
|
if (_syncing) |
||||
|
return; |
||||
|
_syncing = true; |
||||
|
HeroPager.SelectedPageIndex = HeroCarousel.SelectedIndex; |
||||
|
_syncing = false; |
||||
|
} |
||||
|
|
||||
|
private void OnPagerIndexChanged(object? sender, PipsPagerSelectedIndexChangedEventArgs e) |
||||
|
{ |
||||
|
if (_syncing) |
||||
|
return; |
||||
|
_syncing = true; |
||||
|
HeroCarousel.SelectedIndex = e.NewIndex; |
||||
|
_syncing = false; |
||||
|
} |
||||
|
|
||||
|
private void OnDrawerMenuSelectionChanged(object? sender, SelectionChangedEventArgs e) |
||||
|
{ |
||||
|
RootDrawer.IsOpen = false; |
||||
|
DrawerMenu.SelectedItem = null; |
||||
|
} |
||||
|
|
||||
|
private void OnHeroPointerPressed(object? sender, PointerPressedEventArgs e) |
||||
|
{ |
||||
|
if (!e.GetCurrentPoint(null).Properties.IsLeftButtonPressed) |
||||
|
return; |
||||
|
_dragStart = e.GetPosition((Visual?)sender); |
||||
|
_isDragging = true; |
||||
|
} |
||||
|
|
||||
|
private void OnHeroPointerReleased(object? sender, PointerReleasedEventArgs e) |
||||
|
{ |
||||
|
if (!_isDragging) |
||||
|
return; |
||||
|
_isDragging = false; |
||||
|
var delta = e.GetPosition((Visual?)sender).X - _dragStart.X; |
||||
|
if (Math.Abs(delta) < SwipeThreshold) |
||||
|
return; |
||||
|
if (delta < 0) |
||||
|
HeroCarousel.Next(); |
||||
|
else |
||||
|
HeroCarousel.Previous(); |
||||
|
} |
||||
|
|
||||
|
private void OnHeroPointerCaptureLost(object? sender, PointerCaptureLostEventArgs e) |
||||
|
{ |
||||
|
_isDragging = false; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,93 @@ |
|||||
|
<UserControl xmlns="https://github.com/avaloniaui" |
||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" |
||||
|
x:Class="ControlCatalog.Pages.CarouselGesturesPage"> |
||||
|
<DockPanel> |
||||
|
<ScrollViewer DockPanel.Dock="Right" Width="260"> |
||||
|
<StackPanel Margin="12" Spacing="8"> |
||||
|
<TextBlock Text="Configuration" FontWeight="SemiBold" FontSize="16" |
||||
|
Foreground="{DynamicResource SystemControlHighlightAccentBrush}" /> |
||||
|
|
||||
|
<TextBlock Text="Options" FontWeight="SemiBold" FontSize="13" /> |
||||
|
|
||||
|
<CheckBox x:Name="SwipeCheck" |
||||
|
Content="Swipe Gesture" |
||||
|
IsChecked="True" |
||||
|
IsCheckedChanged="OnSwipeEnabledChanged" /> |
||||
|
|
||||
|
<CheckBox x:Name="WrapCheck" |
||||
|
Content="Wrap Selection" |
||||
|
IsChecked="False" |
||||
|
IsCheckedChanged="OnWrapSelectionChanged" /> |
||||
|
|
||||
|
<CheckBox x:Name="KeyboardCheck" |
||||
|
Content="Keyboard Navigation" |
||||
|
IsChecked="True" |
||||
|
IsCheckedChanged="OnKeyboardEnabledChanged" /> |
||||
|
|
||||
|
<Separator /> |
||||
|
|
||||
|
<TextBlock Text="Status" FontWeight="SemiBold" FontSize="14" /> |
||||
|
<TextBlock x:Name="StatusText" |
||||
|
Text="Item: 1 / 3" |
||||
|
Opacity="0.7" |
||||
|
TextWrapping="Wrap" /> |
||||
|
<TextBlock x:Name="LastActionText" |
||||
|
Text="Action: —" |
||||
|
Opacity="0.7" |
||||
|
TextWrapping="Wrap" /> |
||||
|
<TextBlock Text="Swipe left/right or use arrow keys to navigate." |
||||
|
FontSize="11" |
||||
|
Opacity="0.5" |
||||
|
TextWrapping="Wrap" /> |
||||
|
</StackPanel> |
||||
|
</ScrollViewer> |
||||
|
|
||||
|
<Border DockPanel.Dock="Right" Width="1" |
||||
|
Background="{DynamicResource SystemControlForegroundBaseMediumLowBrush}" /> |
||||
|
|
||||
|
<Border Margin="12" |
||||
|
BorderBrush="{DynamicResource SystemControlForegroundBaseMediumLowBrush}" |
||||
|
BorderThickness="1" |
||||
|
CornerRadius="6" |
||||
|
ClipToBounds="True"> |
||||
|
<Carousel x:Name="DemoCarousel" |
||||
|
Focusable="True" |
||||
|
IsSwipeEnabled="True" |
||||
|
Height="300"> |
||||
|
<Carousel.PageTransition> |
||||
|
<PageSlide Duration="0.25" Orientation="Horizontal" /> |
||||
|
</Carousel.PageTransition> |
||||
|
|
||||
|
<Border Margin="14,12" CornerRadius="12" ClipToBounds="True"> |
||||
|
<Grid> |
||||
|
<Image Source="/Assets/delicate-arch-896885_640.jpg" Stretch="UniformToFill" /> |
||||
|
<Border Background="#80000000" VerticalAlignment="Bottom" Padding="12"> |
||||
|
<TextBlock Text="Item 1: Delicate Arch" Foreground="White" |
||||
|
HorizontalAlignment="Center" FontWeight="SemiBold" /> |
||||
|
</Border> |
||||
|
</Grid> |
||||
|
</Border> |
||||
|
|
||||
|
<Border Margin="14,12" CornerRadius="12" ClipToBounds="True"> |
||||
|
<Grid> |
||||
|
<Image Source="/Assets/hirsch-899118_640.jpg" Stretch="UniformToFill" /> |
||||
|
<Border Background="#80000000" VerticalAlignment="Bottom" Padding="12"> |
||||
|
<TextBlock Text="Item 2: Hirsch" Foreground="White" |
||||
|
HorizontalAlignment="Center" FontWeight="SemiBold" /> |
||||
|
</Border> |
||||
|
</Grid> |
||||
|
</Border> |
||||
|
|
||||
|
<Border Margin="14,12" CornerRadius="12" ClipToBounds="True"> |
||||
|
<Grid> |
||||
|
<Image Source="/Assets/maple-leaf-888807_640.jpg" Stretch="UniformToFill" /> |
||||
|
<Border Background="#80000000" VerticalAlignment="Bottom" Padding="12"> |
||||
|
<TextBlock Text="Item 3: Maple Leaf" Foreground="White" |
||||
|
HorizontalAlignment="Center" FontWeight="SemiBold" /> |
||||
|
</Border> |
||||
|
</Grid> |
||||
|
</Border> |
||||
|
</Carousel> |
||||
|
</Border> |
||||
|
</DockPanel> |
||||
|
</UserControl> |
||||
@ -0,0 +1,59 @@ |
|||||
|
using Avalonia.Controls; |
||||
|
using Avalonia.Input; |
||||
|
using Avalonia.Interactivity; |
||||
|
|
||||
|
namespace ControlCatalog.Pages |
||||
|
{ |
||||
|
public partial class CarouselGesturesPage : UserControl |
||||
|
{ |
||||
|
private bool _keyboardEnabled = true; |
||||
|
|
||||
|
public CarouselGesturesPage() |
||||
|
{ |
||||
|
InitializeComponent(); |
||||
|
DemoCarousel.AddHandler(InputElement.KeyDownEvent, OnKeyDown, handledEventsToo: true); |
||||
|
DemoCarousel.SelectionChanged += OnSelectionChanged; |
||||
|
DemoCarousel.Loaded += (_, _) => DemoCarousel.Focus(); |
||||
|
} |
||||
|
|
||||
|
private void OnKeyDown(object? sender, KeyEventArgs e) |
||||
|
{ |
||||
|
if (!_keyboardEnabled) |
||||
|
return; |
||||
|
|
||||
|
switch (e.Key) |
||||
|
{ |
||||
|
case Key.Left: |
||||
|
case Key.Up: |
||||
|
LastActionText.Text = $"Action: Key {e.Key} (Previous)"; |
||||
|
break; |
||||
|
case Key.Right: |
||||
|
case Key.Down: |
||||
|
LastActionText.Text = $"Action: Key {e.Key} (Next)"; |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private void OnSelectionChanged(object? sender, SelectionChangedEventArgs e) |
||||
|
{ |
||||
|
StatusText.Text = $"Item: {DemoCarousel.SelectedIndex + 1} / {DemoCarousel.ItemCount}"; |
||||
|
if (DemoCarousel.IsSwiping) |
||||
|
LastActionText.Text = "Action: Swipe"; |
||||
|
} |
||||
|
|
||||
|
private void OnSwipeEnabledChanged(object? sender, RoutedEventArgs e) |
||||
|
{ |
||||
|
DemoCarousel.IsSwipeEnabled = SwipeCheck.IsChecked == true; |
||||
|
} |
||||
|
|
||||
|
private void OnWrapSelectionChanged(object? sender, RoutedEventArgs e) |
||||
|
{ |
||||
|
DemoCarousel.WrapSelection = WrapCheck.IsChecked == true; |
||||
|
} |
||||
|
|
||||
|
private void OnKeyboardEnabledChanged(object? sender, RoutedEventArgs e) |
||||
|
{ |
||||
|
_keyboardEnabled = KeyboardCheck.IsChecked == true; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,74 @@ |
|||||
|
<UserControl xmlns="https://github.com/avaloniaui" |
||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" |
||||
|
x:Class="ControlCatalog.Pages.CarouselGettingStartedPage"> |
||||
|
<DockPanel> |
||||
|
<ScrollViewer DockPanel.Dock="Right" Width="260"> |
||||
|
<StackPanel Margin="12" Spacing="8"> |
||||
|
<TextBlock Text="Configuration" FontWeight="SemiBold" FontSize="16" |
||||
|
Foreground="{DynamicResource SystemControlHighlightAccentBrush}" /> |
||||
|
|
||||
|
<TextBlock Text="Navigation" FontWeight="SemiBold" FontSize="13" /> |
||||
|
|
||||
|
<Button x:Name="PreviousButton" |
||||
|
Content="Previous" |
||||
|
HorizontalAlignment="Stretch" /> |
||||
|
<Button x:Name="NextButton" |
||||
|
Content="Next" |
||||
|
HorizontalAlignment="Stretch" /> |
||||
|
|
||||
|
<Separator /> |
||||
|
|
||||
|
<TextBlock Text="Status" FontWeight="SemiBold" FontSize="14" /> |
||||
|
<TextBlock x:Name="StatusText" |
||||
|
Text="Item: 1 / 3" |
||||
|
Opacity="0.7" |
||||
|
TextWrapping="Wrap" /> |
||||
|
</StackPanel> |
||||
|
</ScrollViewer> |
||||
|
|
||||
|
<Border DockPanel.Dock="Right" Width="1" |
||||
|
Background="{DynamicResource SystemControlForegroundBaseMediumLowBrush}" /> |
||||
|
|
||||
|
<Border Margin="12" |
||||
|
BorderBrush="{DynamicResource SystemControlForegroundBaseMediumLowBrush}" |
||||
|
BorderThickness="1" |
||||
|
CornerRadius="6" |
||||
|
ClipToBounds="True"> |
||||
|
<Carousel x:Name="DemoCarousel" Height="300" IsSwipeEnabled="True"> |
||||
|
<Carousel.PageTransition> |
||||
|
<PageSlide Duration="0.25" Orientation="Horizontal" /> |
||||
|
</Carousel.PageTransition> |
||||
|
|
||||
|
<Border Margin="14,12" CornerRadius="12" ClipToBounds="True"> |
||||
|
<Grid> |
||||
|
<Image Source="/Assets/delicate-arch-896885_640.jpg" Stretch="UniformToFill" /> |
||||
|
<Border Background="#80000000" VerticalAlignment="Bottom" Padding="12"> |
||||
|
<TextBlock Text="Item 1: Delicate Arch" Foreground="White" |
||||
|
HorizontalAlignment="Center" FontWeight="SemiBold" /> |
||||
|
</Border> |
||||
|
</Grid> |
||||
|
</Border> |
||||
|
|
||||
|
<Border Margin="14,12" CornerRadius="12" ClipToBounds="True"> |
||||
|
<Grid> |
||||
|
<Image Source="/Assets/hirsch-899118_640.jpg" Stretch="UniformToFill" /> |
||||
|
<Border Background="#80000000" VerticalAlignment="Bottom" Padding="12"> |
||||
|
<TextBlock Text="Item 2: Hirsch" Foreground="White" |
||||
|
HorizontalAlignment="Center" FontWeight="SemiBold" /> |
||||
|
</Border> |
||||
|
</Grid> |
||||
|
</Border> |
||||
|
|
||||
|
<Border Margin="14,12" CornerRadius="12" ClipToBounds="True"> |
||||
|
<Grid> |
||||
|
<Image Source="/Assets/maple-leaf-888807_640.jpg" Stretch="UniformToFill" /> |
||||
|
<Border Background="#80000000" VerticalAlignment="Bottom" Padding="12"> |
||||
|
<TextBlock Text="Item 3: Maple Leaf" Foreground="White" |
||||
|
HorizontalAlignment="Center" FontWeight="SemiBold" /> |
||||
|
</Border> |
||||
|
</Grid> |
||||
|
</Border> |
||||
|
</Carousel> |
||||
|
</Border> |
||||
|
</DockPanel> |
||||
|
</UserControl> |
||||
@ -0,0 +1,40 @@ |
|||||
|
using Avalonia.Controls; |
||||
|
using Avalonia.Interactivity; |
||||
|
|
||||
|
namespace ControlCatalog.Pages |
||||
|
{ |
||||
|
public partial class CarouselGettingStartedPage : UserControl |
||||
|
{ |
||||
|
public CarouselGettingStartedPage() |
||||
|
{ |
||||
|
InitializeComponent(); |
||||
|
PreviousButton.Click += OnPrevious; |
||||
|
NextButton.Click += OnNext; |
||||
|
DemoCarousel.SelectionChanged += OnSelectionChanged; |
||||
|
} |
||||
|
|
||||
|
private void OnPrevious(object? sender, RoutedEventArgs e) |
||||
|
{ |
||||
|
DemoCarousel.Previous(); |
||||
|
UpdateStatus(); |
||||
|
} |
||||
|
|
||||
|
private void OnNext(object? sender, RoutedEventArgs e) |
||||
|
{ |
||||
|
DemoCarousel.Next(); |
||||
|
UpdateStatus(); |
||||
|
} |
||||
|
|
||||
|
private void OnSelectionChanged(object? sender, SelectionChangedEventArgs e) |
||||
|
{ |
||||
|
UpdateStatus(); |
||||
|
} |
||||
|
|
||||
|
private void UpdateStatus() |
||||
|
{ |
||||
|
var index = DemoCarousel.SelectedIndex + 1; |
||||
|
var count = DemoCarousel.ItemCount; |
||||
|
StatusText.Text = $"Item: {index} / {count}"; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,140 @@ |
|||||
|
<UserControl xmlns="https://github.com/avaloniaui" |
||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" |
||||
|
x:Class="ControlCatalog.Pages.CarouselMultiItemPage"> |
||||
|
<DockPanel> |
||||
|
<ScrollViewer DockPanel.Dock="Right" Width="260"> |
||||
|
<StackPanel Margin="12" Spacing="8"> |
||||
|
<TextBlock Text="Configuration" FontWeight="SemiBold" FontSize="16" |
||||
|
Foreground="{DynamicResource SystemControlHighlightAccentBrush}" /> |
||||
|
|
||||
|
<TextBlock Text="Navigation" FontWeight="SemiBold" FontSize="13" /> |
||||
|
<Button x:Name="PreviousButton" Content="Previous" HorizontalAlignment="Stretch" /> |
||||
|
<Button x:Name="NextButton" Content="Next" HorizontalAlignment="Stretch" /> |
||||
|
|
||||
|
<Separator /> |
||||
|
|
||||
|
<TextBlock Text="Viewport Fraction" FontWeight="SemiBold" FontSize="13" /> |
||||
|
<TextBlock TextWrapping="Wrap" FontSize="11" Opacity="0.6" |
||||
|
Text="Values below 1.0 show adjacent items peeking into the viewport." /> |
||||
|
<Grid ColumnDefinitions="*,48" ColumnSpacing="8"> |
||||
|
<Slider x:Name="ViewportSlider" |
||||
|
Minimum="0.2" Maximum="1.0" Value="0.5" |
||||
|
TickFrequency="0.01" IsSnapToTickEnabled="True" |
||||
|
HorizontalAlignment="Stretch" |
||||
|
ValueChanged="OnViewportFractionChanged" /> |
||||
|
<TextBlock x:Name="ViewportLabel" Grid.Column="1" |
||||
|
Text="0.50" VerticalAlignment="Center" |
||||
|
HorizontalAlignment="Right" FontWeight="SemiBold" /> |
||||
|
</Grid> |
||||
|
<TextBlock x:Name="ViewportHint" |
||||
|
Text="~2 items visible." |
||||
|
FontSize="11" Opacity="0.6" TextWrapping="Wrap" /> |
||||
|
|
||||
|
<Separator /> |
||||
|
|
||||
|
<TextBlock Text="Options" FontWeight="SemiBold" FontSize="13" /> |
||||
|
<CheckBox x:Name="WrapCheck" Content="Wrap Selection" IsChecked="False" |
||||
|
IsCheckedChanged="OnWrapChanged" /> |
||||
|
<CheckBox x:Name="SwipeCheck" Content="Swipe / Drag" IsChecked="True" |
||||
|
IsCheckedChanged="OnSwipeChanged" /> |
||||
|
|
||||
|
<Separator /> |
||||
|
|
||||
|
<TextBlock Text="Status" FontWeight="SemiBold" FontSize="14" /> |
||||
|
<TextBlock x:Name="StatusText" Text="Item: 1 / 5" |
||||
|
Opacity="0.7" TextWrapping="Wrap" /> |
||||
|
</StackPanel> |
||||
|
</ScrollViewer> |
||||
|
|
||||
|
<Border DockPanel.Dock="Right" Width="1" |
||||
|
Background="{DynamicResource SystemControlForegroundBaseMediumLowBrush}" /> |
||||
|
|
||||
|
<Border Margin="12" |
||||
|
BorderBrush="{DynamicResource SystemControlForegroundBaseMediumLowBrush}" |
||||
|
BorderThickness="1" CornerRadius="6" ClipToBounds="True"> |
||||
|
<Carousel x:Name="DemoCarousel" |
||||
|
Height="280" |
||||
|
ViewportFraction="0.5" |
||||
|
IsSwipeEnabled="True"> |
||||
|
<Carousel.PageTransition> |
||||
|
<PageSlide Duration="0.3" Orientation="Horizontal" /> |
||||
|
</Carousel.PageTransition> |
||||
|
|
||||
|
<Border Margin="6,12" CornerRadius="14" ClipToBounds="True"> |
||||
|
<Border.Background> |
||||
|
<LinearGradientBrush StartPoint="0,0" EndPoint="1,1"> |
||||
|
<GradientStop Color="#3525CD" Offset="0" /> |
||||
|
<GradientStop Color="#6B5CE7" Offset="1" /> |
||||
|
</LinearGradientBrush> |
||||
|
</Border.Background> |
||||
|
<StackPanel VerticalAlignment="Center" HorizontalAlignment="Center" Spacing="8"> |
||||
|
<TextBlock Text="01" FontSize="52" FontWeight="Bold" Foreground="White" |
||||
|
HorizontalAlignment="Center" LetterSpacing="-2" /> |
||||
|
<TextBlock Text="Neon Pulse" FontSize="15" FontWeight="SemiBold" |
||||
|
Foreground="#C3C0FF" HorizontalAlignment="Center" /> |
||||
|
</StackPanel> |
||||
|
</Border> |
||||
|
|
||||
|
<Border Margin="6,12" CornerRadius="14" ClipToBounds="True"> |
||||
|
<Border.Background> |
||||
|
<LinearGradientBrush StartPoint="0,0" EndPoint="1,1"> |
||||
|
<GradientStop Color="#0891B2" Offset="0" /> |
||||
|
<GradientStop Color="#06B6D4" Offset="1" /> |
||||
|
</LinearGradientBrush> |
||||
|
</Border.Background> |
||||
|
<StackPanel VerticalAlignment="Center" HorizontalAlignment="Center" Spacing="8"> |
||||
|
<TextBlock Text="02" FontSize="52" FontWeight="Bold" Foreground="White" |
||||
|
HorizontalAlignment="Center" LetterSpacing="-2" /> |
||||
|
<TextBlock Text="Ephemeral Blue" FontSize="15" FontWeight="SemiBold" |
||||
|
Foreground="#BAF0FA" HorizontalAlignment="Center" /> |
||||
|
</StackPanel> |
||||
|
</Border> |
||||
|
|
||||
|
<Border Margin="6,12" CornerRadius="14" ClipToBounds="True"> |
||||
|
<Border.Background> |
||||
|
<LinearGradientBrush StartPoint="0,0" EndPoint="1,1"> |
||||
|
<GradientStop Color="#059669" Offset="0" /> |
||||
|
<GradientStop Color="#10B981" Offset="1" /> |
||||
|
</LinearGradientBrush> |
||||
|
</Border.Background> |
||||
|
<StackPanel VerticalAlignment="Center" HorizontalAlignment="Center" Spacing="8"> |
||||
|
<TextBlock Text="03" FontSize="52" FontWeight="Bold" Foreground="White" |
||||
|
HorizontalAlignment="Center" LetterSpacing="-2" /> |
||||
|
<TextBlock Text="Forest Forms" FontSize="15" FontWeight="SemiBold" |
||||
|
Foreground="#A7F3D0" HorizontalAlignment="Center" /> |
||||
|
</StackPanel> |
||||
|
</Border> |
||||
|
|
||||
|
<Border Margin="6,12" CornerRadius="14" ClipToBounds="True"> |
||||
|
<Border.Background> |
||||
|
<LinearGradientBrush StartPoint="0,0" EndPoint="1,1"> |
||||
|
<GradientStop Color="#D97706" Offset="0" /> |
||||
|
<GradientStop Color="#F59E0B" Offset="1" /> |
||||
|
</LinearGradientBrush> |
||||
|
</Border.Background> |
||||
|
<StackPanel VerticalAlignment="Center" HorizontalAlignment="Center" Spacing="8"> |
||||
|
<TextBlock Text="04" FontSize="52" FontWeight="Bold" Foreground="White" |
||||
|
HorizontalAlignment="Center" LetterSpacing="-2" /> |
||||
|
<TextBlock Text="Golden Hour" FontSize="15" FontWeight="SemiBold" |
||||
|
Foreground="#FDE68A" HorizontalAlignment="Center" /> |
||||
|
</StackPanel> |
||||
|
</Border> |
||||
|
|
||||
|
<Border Margin="6,12" CornerRadius="14" ClipToBounds="True"> |
||||
|
<Border.Background> |
||||
|
<LinearGradientBrush StartPoint="0,0" EndPoint="1,1"> |
||||
|
<GradientStop Color="#BE185D" Offset="0" /> |
||||
|
<GradientStop Color="#EC4899" Offset="1" /> |
||||
|
</LinearGradientBrush> |
||||
|
</Border.Background> |
||||
|
<StackPanel VerticalAlignment="Center" HorizontalAlignment="Center" Spacing="8"> |
||||
|
<TextBlock Text="05" FontSize="52" FontWeight="Bold" Foreground="White" |
||||
|
HorizontalAlignment="Center" LetterSpacing="-2" /> |
||||
|
<TextBlock Text="Crimson Wave" FontSize="15" FontWeight="SemiBold" |
||||
|
Foreground="#FBCFE8" HorizontalAlignment="Center" /> |
||||
|
</StackPanel> |
||||
|
</Border> |
||||
|
</Carousel> |
||||
|
</Border> |
||||
|
</DockPanel> |
||||
|
</UserControl> |
||||
@ -0,0 +1,47 @@ |
|||||
|
using System; |
||||
|
using Avalonia.Controls; |
||||
|
using Avalonia.Controls.Primitives; |
||||
|
using Avalonia.Interactivity; |
||||
|
|
||||
|
namespace ControlCatalog.Pages |
||||
|
{ |
||||
|
public partial class CarouselMultiItemPage : UserControl |
||||
|
{ |
||||
|
public CarouselMultiItemPage() |
||||
|
{ |
||||
|
InitializeComponent(); |
||||
|
PreviousButton.Click += (_, _) => DemoCarousel.Previous(); |
||||
|
NextButton.Click += (_, _) => DemoCarousel.Next(); |
||||
|
DemoCarousel.SelectionChanged += OnSelectionChanged; |
||||
|
} |
||||
|
|
||||
|
private void OnViewportFractionChanged(object? sender, RangeBaseValueChangedEventArgs e) |
||||
|
{ |
||||
|
if (DemoCarousel is null) |
||||
|
return; |
||||
|
var value = Math.Round(e.NewValue, 2); |
||||
|
DemoCarousel.ViewportFraction = value; |
||||
|
ViewportLabel.Text = value.ToString("0.00"); |
||||
|
ViewportHint.Text = value >= 1d ? "1.00 — single full item." : $"~{1d / value:0.#} items visible."; |
||||
|
} |
||||
|
|
||||
|
private void OnWrapChanged(object? sender, RoutedEventArgs e) |
||||
|
{ |
||||
|
if (DemoCarousel is null) |
||||
|
return; |
||||
|
DemoCarousel.WrapSelection = WrapCheck.IsChecked == true; |
||||
|
} |
||||
|
|
||||
|
private void OnSwipeChanged(object? sender, RoutedEventArgs e) |
||||
|
{ |
||||
|
if (DemoCarousel is null) |
||||
|
return; |
||||
|
DemoCarousel.IsSwipeEnabled = SwipeCheck.IsChecked == true; |
||||
|
} |
||||
|
|
||||
|
private void OnSelectionChanged(object? sender, SelectionChangedEventArgs e) |
||||
|
{ |
||||
|
StatusText.Text = $"Item: {DemoCarousel.SelectedIndex + 1} / {DemoCarousel.ItemCount}"; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,115 @@ |
|||||
|
<UserControl xmlns="https://github.com/avaloniaui" |
||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" |
||||
|
x:Class="ControlCatalog.Pages.CarouselPageCustomizationPage"> |
||||
|
<DockPanel> |
||||
|
<ScrollViewer DockPanel.Dock="Right" Width="220"> |
||||
|
<StackPanel Margin="12" Spacing="8"> |
||||
|
<TextBlock Text="Configuration" FontWeight="SemiBold" FontSize="16" |
||||
|
Foreground="{DynamicResource SystemControlHighlightAccentBrush}" /> |
||||
|
|
||||
|
<TextBlock Text="Slide Direction" FontWeight="SemiBold" FontSize="13" /> |
||||
|
<ComboBox x:Name="OrientationCombo" SelectedIndex="0" |
||||
|
SelectionChanged="OnOrientationChanged" |
||||
|
HorizontalAlignment="Stretch"> |
||||
|
<ComboBoxItem Content="Horizontal" /> |
||||
|
<ComboBoxItem Content="Vertical" /> |
||||
|
</ComboBox> |
||||
|
|
||||
|
<Separator /> |
||||
|
|
||||
|
<TextBlock Text="Navigate" FontWeight="SemiBold" FontSize="13" /> |
||||
|
<StackPanel Spacing="6"> |
||||
|
<Button Content="Previous" Click="OnPrevious" HorizontalAlignment="Stretch" /> |
||||
|
<Button Content="Next" Click="OnNext" HorizontalAlignment="Stretch" /> |
||||
|
</StackPanel> |
||||
|
|
||||
|
<Separator /> |
||||
|
|
||||
|
<TextBlock Text="Status" FontWeight="SemiBold" FontSize="13" /> |
||||
|
<TextBlock x:Name="StatusText" Text="—" Opacity="0.7" TextWrapping="Wrap" /> |
||||
|
</StackPanel> |
||||
|
</ScrollViewer> |
||||
|
|
||||
|
<Border DockPanel.Dock="Right" Width="1" |
||||
|
Background="{DynamicResource SystemControlForegroundBaseMediumLowBrush}" /> |
||||
|
|
||||
|
<Border Margin="12" |
||||
|
BorderBrush="{DynamicResource SystemControlForegroundBaseMediumLowBrush}" |
||||
|
BorderThickness="1" |
||||
|
CornerRadius="6" |
||||
|
ClipToBounds="True"> |
||||
|
<Panel> |
||||
|
<CarouselPage x:Name="DemoCarousel"> |
||||
|
<ContentPage Header="Sunrise" |
||||
|
Background="#FFFDE68A" |
||||
|
HorizontalContentAlignment="Stretch" |
||||
|
VerticalContentAlignment="Stretch"> |
||||
|
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center" Spacing="8"> |
||||
|
<Border Width="64" Height="64" CornerRadius="32" |
||||
|
Background="#F59E0B" /> |
||||
|
<TextBlock Text="Sunrise" FontSize="28" FontWeight="Bold" |
||||
|
Foreground="#92400E" HorizontalAlignment="Center" /> |
||||
|
<TextBlock Text="A new day begins. Warm golden hues fill the horizon." |
||||
|
FontSize="13" Foreground="#92400E" Opacity="0.8" |
||||
|
TextWrapping="Wrap" TextAlignment="Center" MaxWidth="240" /> |
||||
|
</StackPanel> |
||||
|
</ContentPage> |
||||
|
<ContentPage Header="Ocean" |
||||
|
Background="#FFBFDBFE" |
||||
|
HorizontalContentAlignment="Stretch" |
||||
|
VerticalContentAlignment="Stretch"> |
||||
|
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center" Spacing="8"> |
||||
|
<Border Width="64" Height="64" CornerRadius="32" |
||||
|
Background="#3B82F6" /> |
||||
|
<TextBlock Text="Ocean" FontSize="28" FontWeight="Bold" |
||||
|
Foreground="#1E3A5F" HorizontalAlignment="Center" /> |
||||
|
<TextBlock Text="Vast blue waters stretch beyond what the eye can see." |
||||
|
FontSize="13" Foreground="#1E3A5F" Opacity="0.8" |
||||
|
TextWrapping="Wrap" TextAlignment="Center" MaxWidth="240" /> |
||||
|
</StackPanel> |
||||
|
</ContentPage> |
||||
|
<ContentPage Header="Forest" |
||||
|
Background="#FFBBF7D0" |
||||
|
HorizontalContentAlignment="Stretch" |
||||
|
VerticalContentAlignment="Stretch"> |
||||
|
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center" Spacing="8"> |
||||
|
<Border Width="64" Height="64" CornerRadius="32" |
||||
|
Background="#22C55E" /> |
||||
|
<TextBlock Text="Forest" FontSize="28" FontWeight="Bold" |
||||
|
Foreground="#14532D" HorizontalAlignment="Center" /> |
||||
|
<TextBlock Text="Ancient trees whisper in the quiet woodland breeze." |
||||
|
FontSize="13" Foreground="#14532D" Opacity="0.8" |
||||
|
TextWrapping="Wrap" TextAlignment="Center" MaxWidth="240" /> |
||||
|
</StackPanel> |
||||
|
</ContentPage> |
||||
|
<ContentPage Header="Night" |
||||
|
Background="#1E1B4B" |
||||
|
HorizontalContentAlignment="Stretch" |
||||
|
VerticalContentAlignment="Stretch"> |
||||
|
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center" Spacing="8"> |
||||
|
<Border Width="64" Height="64" CornerRadius="32" |
||||
|
Background="#6366F1" /> |
||||
|
<TextBlock Text="Night" FontSize="28" FontWeight="Bold" |
||||
|
Foreground="#C7D2FE" HorizontalAlignment="Center" /> |
||||
|
<TextBlock Text="Stars emerge as the world quiets into peaceful darkness." |
||||
|
FontSize="13" Foreground="#C7D2FE" Opacity="0.8" |
||||
|
TextWrapping="Wrap" TextAlignment="Center" MaxWidth="240" /> |
||||
|
</StackPanel> |
||||
|
</ContentPage> |
||||
|
</CarouselPage> |
||||
|
|
||||
|
<!-- Page indicator dots --> |
||||
|
<Border VerticalAlignment="Bottom" HorizontalAlignment="Center" |
||||
|
Margin="0,0,0,12" CornerRadius="8" Background="#44000000" |
||||
|
Padding="10,4"> |
||||
|
<StackPanel Orientation="Horizontal" Spacing="6"> |
||||
|
<Ellipse x:Name="Dot0" Width="8" Height="8" Fill="White" /> |
||||
|
<Ellipse x:Name="Dot1" Width="8" Height="8" Fill="White" Opacity="0.4" /> |
||||
|
<Ellipse x:Name="Dot2" Width="8" Height="8" Fill="White" Opacity="0.4" /> |
||||
|
<Ellipse x:Name="Dot3" Width="8" Height="8" Fill="White" Opacity="0.4" /> |
||||
|
</StackPanel> |
||||
|
</Border> |
||||
|
</Panel> |
||||
|
</Border> |
||||
|
</DockPanel> |
||||
|
</UserControl> |
||||
@ -0,0 +1,79 @@ |
|||||
|
using System; |
||||
|
using System.Collections; |
||||
|
using Avalonia.Animation; |
||||
|
using Avalonia.Controls; |
||||
|
using Avalonia.Interactivity; |
||||
|
|
||||
|
namespace ControlCatalog.Pages |
||||
|
{ |
||||
|
public partial class CarouselPageCustomizationPage : UserControl |
||||
|
{ |
||||
|
public CarouselPageCustomizationPage() |
||||
|
{ |
||||
|
InitializeComponent(); |
||||
|
Loaded += OnLoaded; |
||||
|
Unloaded += OnUnloaded; |
||||
|
} |
||||
|
|
||||
|
private void OnLoaded(object? sender, RoutedEventArgs e) |
||||
|
{ |
||||
|
DemoCarousel.PageTransition = new PageSlide(TimeSpan.FromMilliseconds(300), PageSlide.SlideAxis.Horizontal); |
||||
|
DemoCarousel.SelectionChanged += OnSelectionChanged; |
||||
|
UpdateDots(DemoCarousel.SelectedIndex); |
||||
|
UpdateStatus(); |
||||
|
} |
||||
|
|
||||
|
private void OnUnloaded(object? sender, RoutedEventArgs e) |
||||
|
{ |
||||
|
DemoCarousel.SelectionChanged -= OnSelectionChanged; |
||||
|
} |
||||
|
|
||||
|
private void OnSelectionChanged(object? sender, PageSelectionChangedEventArgs e) |
||||
|
{ |
||||
|
UpdateDots(DemoCarousel.SelectedIndex); |
||||
|
UpdateStatus(); |
||||
|
} |
||||
|
|
||||
|
private void OnOrientationChanged(object? sender, SelectionChangedEventArgs e) |
||||
|
{ |
||||
|
if (DemoCarousel == null) |
||||
|
return; |
||||
|
|
||||
|
var axis = OrientationCombo.SelectedIndex == 1 |
||||
|
? PageSlide.SlideAxis.Vertical |
||||
|
: PageSlide.SlideAxis.Horizontal; |
||||
|
|
||||
|
DemoCarousel.PageTransition = new PageSlide(TimeSpan.FromMilliseconds(300), axis); |
||||
|
UpdateStatus(); |
||||
|
} |
||||
|
|
||||
|
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 UpdateDots(int selectedIndex) |
||||
|
{ |
||||
|
Dot0.Opacity = selectedIndex == 0 ? 1.0 : 0.4; |
||||
|
Dot1.Opacity = selectedIndex == 1 ? 1.0 : 0.4; |
||||
|
Dot2.Opacity = selectedIndex == 2 ? 1.0 : 0.4; |
||||
|
Dot3.Opacity = selectedIndex == 3 ? 1.0 : 0.4; |
||||
|
} |
||||
|
|
||||
|
private void UpdateStatus() |
||||
|
{ |
||||
|
if (StatusText == null) return; |
||||
|
var pageCount = (DemoCarousel.Pages as IList)?.Count ?? 0; |
||||
|
var axis = OrientationCombo?.SelectedIndex == 1 ? "Vertical" : "Horizontal"; |
||||
|
StatusText.Text = $"Page {DemoCarousel.SelectedIndex + 1} of {pageCount} | {axis}"; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,44 @@ |
|||||
|
<UserControl xmlns="https://github.com/avaloniaui" |
||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" |
||||
|
x:Class="ControlCatalog.Pages.CarouselPageDataTemplatePage"> |
||||
|
<DockPanel> |
||||
|
<ScrollViewer DockPanel.Dock="Right" Width="240"> |
||||
|
<StackPanel Margin="12" Spacing="8"> |
||||
|
<TextBlock Text="Data Templates" FontWeight="SemiBold" FontSize="16" |
||||
|
Foreground="{DynamicResource SystemControlHighlightAccentBrush}" /> |
||||
|
|
||||
|
<TextBlock FontSize="12" Opacity="0.7" TextWrapping="Wrap" |
||||
|
Text="Bind a CarouselPage to a view-model collection, render each item with PageTemplate, and switch templates at runtime." /> |
||||
|
|
||||
|
<Separator /> |
||||
|
|
||||
|
<Button Content="Add Page" Click="OnAddPage" HorizontalAlignment="Stretch" /> |
||||
|
<Button Content="Remove Last" Click="OnRemovePage" HorizontalAlignment="Stretch" /> |
||||
|
<Button Content="Switch Template" Click="OnSwitchTemplate" HorizontalAlignment="Stretch" /> |
||||
|
|
||||
|
<Separator /> |
||||
|
|
||||
|
<TextBlock Text="Navigate" FontWeight="SemiBold" FontSize="13" /> |
||||
|
<StackPanel Spacing="6"> |
||||
|
<Button Content="Previous" Click="OnPrevious" HorizontalAlignment="Stretch" /> |
||||
|
<Button Content="Next" Click="OnNext" HorizontalAlignment="Stretch" /> |
||||
|
</StackPanel> |
||||
|
|
||||
|
<Separator /> |
||||
|
|
||||
|
<TextBlock x:Name="StatusText" Text="4 pages" Opacity="0.7" /> |
||||
|
</StackPanel> |
||||
|
</ScrollViewer> |
||||
|
|
||||
|
<Border DockPanel.Dock="Right" Width="1" |
||||
|
Background="{DynamicResource SystemControlForegroundBaseMediumLowBrush}" /> |
||||
|
|
||||
|
<Border Margin="12" |
||||
|
BorderBrush="{DynamicResource SystemControlForegroundBaseMediumLowBrush}" |
||||
|
BorderThickness="1" |
||||
|
CornerRadius="6" |
||||
|
ClipToBounds="True"> |
||||
|
<Panel x:Name="CarouselHost" /> |
||||
|
</Border> |
||||
|
</DockPanel> |
||||
|
</UserControl> |
||||
@ -0,0 +1,209 @@ |
|||||
|
using System.Collections.ObjectModel; |
||||
|
using Avalonia; |
||||
|
using Avalonia.Controls; |
||||
|
using Avalonia.Controls.Templates; |
||||
|
using Avalonia.Interactivity; |
||||
|
using Avalonia.Layout; |
||||
|
using Avalonia.Media; |
||||
|
using AvaCarouselPage = Avalonia.Controls.CarouselPage; |
||||
|
|
||||
|
namespace ControlCatalog.Pages |
||||
|
{ |
||||
|
public partial class CarouselPageDataTemplatePage : UserControl |
||||
|
{ |
||||
|
private sealed class CityViewModel |
||||
|
{ |
||||
|
public string Name { get; } |
||||
|
public string Color { get; } |
||||
|
public string Description { get; } |
||||
|
|
||||
|
public CityViewModel(string name, string color, string description) |
||||
|
{ |
||||
|
Name = name; |
||||
|
Color = color; |
||||
|
Description = description; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private static readonly CityViewModel[] InitialData = |
||||
|
{ |
||||
|
new("Tokyo", "#1565C0", |
||||
|
"The neon-lit capital of Japan, where ancient temples meet futuristic skylines."), |
||||
|
new("Amsterdam", "#2E7D32", "A city of canals, bicycles, and world-class museums."), |
||||
|
new("New York", "#6A1B9A", "The city that never sleeps — a cultural and financial powerhouse."), |
||||
|
new("Sydney", "#B71C1C", "Iconic harbour, golden beaches and the world-famous Opera House."), |
||||
|
}; |
||||
|
|
||||
|
private static readonly CityViewModel[] AddData = |
||||
|
{ |
||||
|
new("Paris", "#E65100", "The city of light, love, and the Eiffel Tower."), |
||||
|
new("Barcelona", "#00695C", "Art, architecture, and vibrant street life on the Mediterranean coast."), |
||||
|
new("Kyoto", "#880E4F", "Japan's ancient capital, a living museum of traditional culture."), |
||||
|
}; |
||||
|
|
||||
|
private readonly ObservableCollection<CityViewModel> _items = new(); |
||||
|
private int _addCounter; |
||||
|
private bool _useCardTemplate = true; |
||||
|
private AvaCarouselPage? _carouselPage; |
||||
|
|
||||
|
public CarouselPageDataTemplatePage() |
||||
|
{ |
||||
|
InitializeComponent(); |
||||
|
Loaded += OnLoaded; |
||||
|
} |
||||
|
|
||||
|
private void OnLoaded(object? sender, RoutedEventArgs e) |
||||
|
{ |
||||
|
if (_carouselPage != null) |
||||
|
return; |
||||
|
|
||||
|
foreach (var vm in InitialData) |
||||
|
_items.Add(vm); |
||||
|
_addCounter = InitialData.Length; |
||||
|
_useCardTemplate = true; |
||||
|
|
||||
|
_carouselPage = new AvaCarouselPage { ItemsSource = _items, PageTemplate = CreatePageTemplate() }; |
||||
|
|
||||
|
_carouselPage.SelectionChanged += OnSelectionChanged; |
||||
|
CarouselHost.Children.Add(_carouselPage); |
||||
|
UpdateStatus(); |
||||
|
} |
||||
|
|
||||
|
private void OnSelectionChanged(object? sender, PageSelectionChangedEventArgs e) => UpdateStatus(); |
||||
|
|
||||
|
private void OnAddPage(object? sender, RoutedEventArgs e) |
||||
|
{ |
||||
|
var idx = _addCounter % AddData.Length; |
||||
|
var vm = AddData[idx]; |
||||
|
var suffix = _addCounter >= AddData.Length ? $" {_addCounter / AddData.Length + 1}" : ""; |
||||
|
_items.Add(new CityViewModel(vm.Name + suffix, vm.Color, vm.Description)); |
||||
|
_addCounter++; |
||||
|
UpdateStatus(); |
||||
|
} |
||||
|
|
||||
|
private void OnRemovePage(object? sender, RoutedEventArgs e) |
||||
|
{ |
||||
|
if (_items.Count > 0) |
||||
|
{ |
||||
|
_items.RemoveAt(_items.Count - 1); |
||||
|
UpdateStatus(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private void OnSwitchTemplate(object? sender, RoutedEventArgs e) |
||||
|
{ |
||||
|
if (_carouselPage == null) |
||||
|
return; |
||||
|
|
||||
|
_useCardTemplate = !_useCardTemplate; |
||||
|
_carouselPage.PageTemplate = CreatePageTemplate(); |
||||
|
} |
||||
|
|
||||
|
private void OnPrevious(object? sender, RoutedEventArgs e) |
||||
|
{ |
||||
|
if (_carouselPage == null) |
||||
|
return; |
||||
|
if (_carouselPage.SelectedIndex > 0) |
||||
|
_carouselPage.SelectedIndex--; |
||||
|
} |
||||
|
|
||||
|
private void OnNext(object? sender, RoutedEventArgs e) |
||||
|
{ |
||||
|
if (_carouselPage == null) |
||||
|
return; |
||||
|
if (_carouselPage.SelectedIndex < _items.Count - 1) |
||||
|
_carouselPage.SelectedIndex++; |
||||
|
} |
||||
|
|
||||
|
private void UpdateStatus() |
||||
|
{ |
||||
|
var count = _items.Count; |
||||
|
var index = _carouselPage?.SelectedIndex ?? -1; |
||||
|
StatusText.Text = count == 0 ? "No pages" : $"Page {index + 1} of {count} (index {index})"; |
||||
|
} |
||||
|
|
||||
|
private IDataTemplate CreatePageTemplate() |
||||
|
{ |
||||
|
return new FuncDataTemplate<CityViewModel>((vm, _) => CreatePage(vm, _useCardTemplate)); |
||||
|
} |
||||
|
|
||||
|
private static ContentPage CreatePage(CityViewModel? vm, bool useCardTemplate) |
||||
|
{ |
||||
|
if (vm is null) |
||||
|
return new ContentPage(); |
||||
|
|
||||
|
return new ContentPage |
||||
|
{ |
||||
|
Header = vm.Name, Content = useCardTemplate ? CreateCardContent(vm) : CreateFeatureContent(vm) |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
private static Control CreateCardContent(CityViewModel vm) |
||||
|
{ |
||||
|
return new StackPanel |
||||
|
{ |
||||
|
HorizontalAlignment = HorizontalAlignment.Center, |
||||
|
VerticalAlignment = VerticalAlignment.Center, |
||||
|
Spacing = 8, |
||||
|
Children = |
||||
|
{ |
||||
|
new TextBlock |
||||
|
{ |
||||
|
Text = vm.Name, |
||||
|
FontSize = 28, |
||||
|
FontWeight = FontWeight.Bold, |
||||
|
Foreground = new SolidColorBrush(Color.Parse(vm.Color)), |
||||
|
HorizontalAlignment = HorizontalAlignment.Center |
||||
|
}, |
||||
|
new TextBlock |
||||
|
{ |
||||
|
Text = vm.Description, |
||||
|
FontSize = 13, |
||||
|
Opacity = 0.7, |
||||
|
TextWrapping = TextWrapping.Wrap, |
||||
|
TextAlignment = TextAlignment.Center, |
||||
|
MaxWidth = 280 |
||||
|
} |
||||
|
} |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
private static Control CreateFeatureContent(CityViewModel vm) |
||||
|
{ |
||||
|
var accent = Color.Parse(vm.Color); |
||||
|
|
||||
|
return new Border |
||||
|
{ |
||||
|
Background = new SolidColorBrush(accent), |
||||
|
Padding = new Thickness(32), |
||||
|
Child = new StackPanel |
||||
|
{ |
||||
|
HorizontalAlignment = HorizontalAlignment.Center, |
||||
|
VerticalAlignment = VerticalAlignment.Center, |
||||
|
Spacing = 12, |
||||
|
Children = |
||||
|
{ |
||||
|
new TextBlock |
||||
|
{ |
||||
|
Text = vm.Name.ToUpperInvariant(), |
||||
|
FontSize = 34, |
||||
|
FontWeight = FontWeight.Bold, |
||||
|
Foreground = Brushes.White, |
||||
|
HorizontalAlignment = HorizontalAlignment.Center |
||||
|
}, |
||||
|
new TextBlock |
||||
|
{ |
||||
|
Text = vm.Description, |
||||
|
FontSize = 15, |
||||
|
Foreground = Brushes.White, |
||||
|
Opacity = 0.88, |
||||
|
TextWrapping = TextWrapping.Wrap, |
||||
|
TextAlignment = TextAlignment.Center, |
||||
|
MaxWidth = 320 |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
}; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,37 @@ |
|||||
|
<UserControl xmlns="https://github.com/avaloniaui" |
||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" |
||||
|
x:Class="ControlCatalog.Pages.CarouselPageEventsPage"> |
||||
|
<DockPanel> |
||||
|
<StackPanel DockPanel.Dock="Right" Width="240" Margin="0,0,0,0"> |
||||
|
<StackPanel Margin="12" Spacing="8"> |
||||
|
<TextBlock Text="Event Log" FontWeight="SemiBold" FontSize="16" |
||||
|
Foreground="{DynamicResource SystemControlHighlightAccentBrush}" /> |
||||
|
|
||||
|
<TextBlock Text="Navigate" FontWeight="SemiBold" FontSize="13" /> |
||||
|
<StackPanel Spacing="6"> |
||||
|
<Button Content="Previous" Click="OnPrevious" HorizontalAlignment="Stretch" /> |
||||
|
<Button Content="Next" Click="OnNext" HorizontalAlignment="Stretch" /> |
||||
|
</StackPanel> |
||||
|
|
||||
|
<Separator /> |
||||
|
|
||||
|
<Button Content="Clear Log" Click="OnClearLog" HorizontalAlignment="Stretch" /> |
||||
|
</StackPanel> |
||||
|
<Border Height="1" Background="{DynamicResource SystemControlForegroundBaseMediumLowBrush}" /> |
||||
|
<ScrollViewer x:Name="LogScrollViewer" VerticalScrollBarVisibility="Auto"> |
||||
|
<TextBlock x:Name="EventLog" Margin="12" FontSize="11" |
||||
|
FontFamily="Courier New, Consolas, monospace" |
||||
|
TextWrapping="Wrap" Opacity="0.85" /> |
||||
|
</ScrollViewer> |
||||
|
</StackPanel> |
||||
|
|
||||
|
<Border DockPanel.Dock="Right" Width="1" |
||||
|
Background="{DynamicResource SystemControlForegroundBaseMediumLowBrush}" /> |
||||
|
|
||||
|
<Border Margin="12" |
||||
|
BorderBrush="{DynamicResource SystemControlForegroundBaseMediumLowBrush}" |
||||
|
BorderThickness="1" CornerRadius="6" ClipToBounds="True"> |
||||
|
<CarouselPage x:Name="DemoCarousel" /> |
||||
|
</Border> |
||||
|
</DockPanel> |
||||
|
</UserControl> |
||||
@ -0,0 +1,92 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using Avalonia.Collections; |
||||
|
using Avalonia.Controls; |
||||
|
using Avalonia.Interactivity; |
||||
|
|
||||
|
namespace ControlCatalog.Pages |
||||
|
{ |
||||
|
public partial class CarouselPageEventsPage : UserControl |
||||
|
{ |
||||
|
private readonly List<string> _log = new(); |
||||
|
|
||||
|
public CarouselPageEventsPage() |
||||
|
{ |
||||
|
InitializeComponent(); |
||||
|
Loaded += OnLoaded; |
||||
|
Unloaded += OnUnloaded; |
||||
|
} |
||||
|
|
||||
|
private void OnLoaded(object? sender, RoutedEventArgs e) |
||||
|
{ |
||||
|
var pageNames = new[] { "Home", "Explore", "Library", "Profile" }; |
||||
|
for (int i = 0; i < pageNames.Length; i++) |
||||
|
{ |
||||
|
var name = pageNames[i]; |
||||
|
var page = new ContentPage |
||||
|
{ |
||||
|
Header = name, |
||||
|
Background = NavigationDemoHelper.GetPageBrush(i), |
||||
|
Content = new TextBlock |
||||
|
{ |
||||
|
Text = $"{name}", |
||||
|
FontSize = 28, |
||||
|
FontWeight = Avalonia.Media.FontWeight.Bold, |
||||
|
HorizontalAlignment = Avalonia.Layout.HorizontalAlignment.Center, |
||||
|
VerticalAlignment = Avalonia.Layout.VerticalAlignment.Center |
||||
|
}, |
||||
|
HorizontalContentAlignment = Avalonia.Layout.HorizontalAlignment.Stretch, |
||||
|
VerticalContentAlignment = Avalonia.Layout.VerticalAlignment.Stretch |
||||
|
}; |
||||
|
|
||||
|
page.NavigatedTo += (_, args) => |
||||
|
AppendLog($"NavigatedTo: {name} (from {(args.PreviousPage as ContentPage)?.Header ?? "—"})"); |
||||
|
page.NavigatedFrom += (_, args) => |
||||
|
AppendLog($"NavigatedFrom: {name} (to {(args.DestinationPage as ContentPage)?.Header ?? "—"})"); |
||||
|
|
||||
|
((Avalonia.Collections.AvaloniaList<Page>)DemoCarousel.Pages!).Add(page); |
||||
|
} |
||||
|
|
||||
|
DemoCarousel.SelectionChanged += OnSelectionChanged; |
||||
|
} |
||||
|
|
||||
|
private void OnSelectionChanged(object? sender, PageSelectionChangedEventArgs e) |
||||
|
{ |
||||
|
AppendLog($"SelectionChanged: {(e.PreviousPage as ContentPage)?.Header ?? "—"} → {(e.CurrentPage as ContentPage)?.Header ?? "—"}"); |
||||
|
} |
||||
|
|
||||
|
private void OnPrevious(object? sender, RoutedEventArgs e) |
||||
|
{ |
||||
|
if (DemoCarousel.SelectedIndex > 0) |
||||
|
DemoCarousel.SelectedIndex--; |
||||
|
} |
||||
|
|
||||
|
private void OnNext(object? sender, RoutedEventArgs e) |
||||
|
{ |
||||
|
var pageCount = ((AvaloniaList<Page>)DemoCarousel.Pages!).Count; |
||||
|
if (DemoCarousel.SelectedIndex < pageCount - 1) |
||||
|
DemoCarousel.SelectedIndex++; |
||||
|
} |
||||
|
|
||||
|
private void OnUnloaded(object? sender, RoutedEventArgs e) |
||||
|
{ |
||||
|
DemoCarousel.SelectionChanged -= OnSelectionChanged; |
||||
|
} |
||||
|
|
||||
|
private void OnClearLog(object? sender, RoutedEventArgs e) |
||||
|
{ |
||||
|
_log.Clear(); |
||||
|
EventLog.Text = string.Empty; |
||||
|
} |
||||
|
|
||||
|
private void AppendLog(string message) |
||||
|
{ |
||||
|
var timestamp = DateTime.Now.ToString("HH:mm:ss.fff"); |
||||
|
_log.Add($"[{timestamp}] {message}"); |
||||
|
if (_log.Count > 50) |
||||
|
_log.RemoveAt(0); |
||||
|
EventLog.Text = string.Join(Environment.NewLine, _log); |
||||
|
LogScrollViewer.ScrollToEnd(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,61 @@ |
|||||
|
<UserControl xmlns="https://github.com/avaloniaui" |
||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" |
||||
|
x:Class="ControlCatalog.Pages.CarouselPageFirstLookPage"> |
||||
|
<DockPanel> |
||||
|
<ScrollViewer DockPanel.Dock="Right" Width="220"> |
||||
|
<StackPanel Margin="12" Spacing="8"> |
||||
|
<TextBlock Text="Configuration" FontWeight="SemiBold" FontSize="16" |
||||
|
Foreground="{DynamicResource SystemControlHighlightAccentBrush}" /> |
||||
|
|
||||
|
<TextBlock Text="Navigation" FontWeight="SemiBold" FontSize="13" /> |
||||
|
<StackPanel Spacing="6"> |
||||
|
<Button Content="Previous" Click="OnPrevious" HorizontalAlignment="Stretch" /> |
||||
|
<Button Content="Next" Click="OnNext" HorizontalAlignment="Stretch" /> |
||||
|
</StackPanel> |
||||
|
|
||||
|
<Separator /> |
||||
|
|
||||
|
<TextBlock Text="Status" FontWeight="SemiBold" FontSize="13" /> |
||||
|
<TextBlock x:Name="StatusText" Text="Page 1 of 3" Opacity="0.7" TextWrapping="Wrap" /> |
||||
|
</StackPanel> |
||||
|
</ScrollViewer> |
||||
|
|
||||
|
<Border DockPanel.Dock="Right" Width="1" |
||||
|
Background="{DynamicResource SystemControlForegroundBaseMediumLowBrush}" /> |
||||
|
|
||||
|
<Border Margin="12" |
||||
|
BorderBrush="{DynamicResource SystemControlForegroundBaseMediumLowBrush}" |
||||
|
BorderThickness="1" CornerRadius="6" ClipToBounds="True"> |
||||
|
<CarouselPage x:Name="DemoCarousel" |
||||
|
SelectionChanged="OnSelectionChanged"> |
||||
|
<ContentPage Header="Welcome"> |
||||
|
<StackPanel Margin="24" Spacing="12" |
||||
|
HorizontalAlignment="Center" VerticalAlignment="Center"> |
||||
|
<TextBlock Text="Welcome" FontSize="28" FontWeight="Bold" |
||||
|
HorizontalAlignment="Center" /> |
||||
|
<TextBlock Text="Swipe left or use the buttons to navigate." |
||||
|
TextWrapping="Wrap" Opacity="0.7" TextAlignment="Center" MaxWidth="280" /> |
||||
|
</StackPanel> |
||||
|
</ContentPage> |
||||
|
<ContentPage Header="Explore"> |
||||
|
<StackPanel Margin="24" Spacing="12" |
||||
|
HorizontalAlignment="Center" VerticalAlignment="Center"> |
||||
|
<TextBlock Text="Explore" FontSize="28" FontWeight="Bold" |
||||
|
HorizontalAlignment="Center" /> |
||||
|
<TextBlock Text="CarouselPage supports scroll-based and transition-based navigation modes." |
||||
|
TextWrapping="Wrap" Opacity="0.7" TextAlignment="Center" MaxWidth="280" /> |
||||
|
</StackPanel> |
||||
|
</ContentPage> |
||||
|
<ContentPage Header="Get Started"> |
||||
|
<StackPanel Margin="24" Spacing="12" |
||||
|
HorizontalAlignment="Center" VerticalAlignment="Center"> |
||||
|
<TextBlock Text="Get Started" FontSize="28" FontWeight="Bold" |
||||
|
HorizontalAlignment="Center" /> |
||||
|
<TextBlock Text="Use SelectedIndex to jump to any page, or assign a PageTransition for animated switching." |
||||
|
TextWrapping="Wrap" Opacity="0.7" TextAlignment="Center" MaxWidth="280" /> |
||||
|
</StackPanel> |
||||
|
</ContentPage> |
||||
|
</CarouselPage> |
||||
|
</Border> |
||||
|
</DockPanel> |
||||
|
</UserControl> |
||||
@ -0,0 +1,35 @@ |
|||||
|
using System.Collections; |
||||
|
using Avalonia.Controls; |
||||
|
using Avalonia.Interactivity; |
||||
|
|
||||
|
namespace ControlCatalog.Pages |
||||
|
{ |
||||
|
public partial class CarouselPageFirstLookPage : UserControl |
||||
|
{ |
||||
|
public CarouselPageFirstLookPage() |
||||
|
{ |
||||
|
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}"; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,64 @@ |
|||||
|
<UserControl xmlns="https://github.com/avaloniaui" |
||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" |
||||
|
x:Class="ControlCatalog.Pages.CarouselPageGesturePage"> |
||||
|
<DockPanel> |
||||
|
<ScrollViewer DockPanel.Dock="Right" Width="220"> |
||||
|
<StackPanel Margin="12" Spacing="8"> |
||||
|
<TextBlock Text="Configuration" FontWeight="SemiBold" FontSize="16" |
||||
|
Foreground="{DynamicResource SystemControlHighlightAccentBrush}" /> |
||||
|
|
||||
|
<TextBlock Text="Gesture Navigation" FontWeight="SemiBold" FontSize="13" /> |
||||
|
<CheckBox x:Name="GestureCheck" Content="IsGestureEnabled" |
||||
|
IsChecked="True" IsCheckedChanged="OnGestureChanged" /> |
||||
|
|
||||
|
<Separator /> |
||||
|
|
||||
|
<TextBlock Text="Keyboard Navigation" FontWeight="SemiBold" FontSize="13" /> |
||||
|
<CheckBox x:Name="KeyboardCheck" Content="IsKeyboardNavigationEnabled" |
||||
|
IsChecked="True" IsCheckedChanged="OnKeyboardChanged" /> |
||||
|
|
||||
|
<Separator /> |
||||
|
|
||||
|
<TextBlock Text="Hints" FontWeight="SemiBold" FontSize="13" /> |
||||
|
<TextBlock Text="• Swipe left/right to navigate (touch)" FontSize="11" Opacity="0.7" TextWrapping="Wrap" /> |
||||
|
<TextBlock Text="• Mouse drag (left button) to navigate" FontSize="11" Opacity="0.7" TextWrapping="Wrap" /> |
||||
|
<TextBlock Text="• Arrow keys / Home / End when focused" FontSize="11" Opacity="0.7" TextWrapping="Wrap" /> |
||||
|
<TextBlock Text="• Mouse wheel scrolls pages" FontSize="11" Opacity="0.7" TextWrapping="Wrap" /> |
||||
|
|
||||
|
<Separator /> |
||||
|
|
||||
|
<TextBlock Text="Status" FontWeight="SemiBold" FontSize="13" /> |
||||
|
<TextBlock x:Name="StatusText" Text="—" Opacity="0.7" TextWrapping="Wrap" /> |
||||
|
</StackPanel> |
||||
|
</ScrollViewer> |
||||
|
|
||||
|
<Border DockPanel.Dock="Right" Width="1" |
||||
|
Background="{DynamicResource SystemControlForegroundBaseMediumLowBrush}" /> |
||||
|
|
||||
|
<Border Margin="12" |
||||
|
BorderBrush="{DynamicResource SystemControlForegroundBaseMediumLowBrush}" |
||||
|
BorderThickness="1" CornerRadius="6" ClipToBounds="True"> |
||||
|
<CarouselPage x:Name="DemoCarousel" |
||||
|
SelectionChanged="OnSelectionChanged"> |
||||
|
<CarouselPage.PageTransition> |
||||
|
<PageSlide Duration="0:0:0.3" Orientation="Horizontal" /> |
||||
|
</CarouselPage.PageTransition> |
||||
|
<ContentPage Header="Page 1" Background="#BBDEFB"> |
||||
|
<TextBlock Text="Page 1 — Swipe or drag to navigate" |
||||
|
HorizontalAlignment="Center" VerticalAlignment="Center" |
||||
|
TextWrapping="Wrap" TextAlignment="Center" MaxWidth="200" FontSize="16" /> |
||||
|
</ContentPage> |
||||
|
<ContentPage Header="Page 2" Background="#C8E6C9"> |
||||
|
<TextBlock Text="Page 2 — Arrow keys also work when focused" |
||||
|
HorizontalAlignment="Center" VerticalAlignment="Center" |
||||
|
TextWrapping="Wrap" TextAlignment="Center" MaxWidth="200" FontSize="16" /> |
||||
|
</ContentPage> |
||||
|
<ContentPage Header="Page 3" Background="#FFE0B2"> |
||||
|
<TextBlock Text="Page 3 — Disable gestures using the panel" |
||||
|
HorizontalAlignment="Center" VerticalAlignment="Center" |
||||
|
TextWrapping="Wrap" TextAlignment="Center" MaxWidth="200" FontSize="16" /> |
||||
|
</ContentPage> |
||||
|
</CarouselPage> |
||||
|
</Border> |
||||
|
</DockPanel> |
||||
|
</UserControl> |
||||
@ -0,0 +1,44 @@ |
|||||
|
using System.Collections; |
||||
|
using Avalonia.Controls; |
||||
|
using Avalonia.Interactivity; |
||||
|
|
||||
|
namespace ControlCatalog.Pages |
||||
|
{ |
||||
|
public partial class CarouselPageGesturePage : UserControl |
||||
|
{ |
||||
|
public CarouselPageGesturePage() |
||||
|
{ |
||||
|
InitializeComponent(); |
||||
|
Loaded += OnLoaded; |
||||
|
} |
||||
|
|
||||
|
private void OnLoaded(object? sender, RoutedEventArgs e) => UpdateStatus(); |
||||
|
|
||||
|
private void OnGestureChanged(object? sender, RoutedEventArgs e) |
||||
|
{ |
||||
|
if (DemoCarousel == null) |
||||
|
return; |
||||
|
DemoCarousel.IsGestureEnabled = GestureCheck.IsChecked == true; |
||||
|
} |
||||
|
|
||||
|
private void OnKeyboardChanged(object? sender, RoutedEventArgs e) |
||||
|
{ |
||||
|
if (DemoCarousel == null) |
||||
|
return; |
||||
|
DemoCarousel.IsKeyboardNavigationEnabled = KeyboardCheck.IsChecked == true; |
||||
|
} |
||||
|
|
||||
|
private void OnSelectionChanged(object? sender, PageSelectionChangedEventArgs e) |
||||
|
{ |
||||
|
UpdateStatus(); |
||||
|
} |
||||
|
|
||||
|
private void UpdateStatus() |
||||
|
{ |
||||
|
if (StatusText == null) |
||||
|
return; |
||||
|
var pageCount = (DemoCarousel.Pages as IList)?.Count ?? 0; |
||||
|
StatusText.Text = $"Page {DemoCarousel.SelectedIndex + 1} of {pageCount}"; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,45 @@ |
|||||
|
<UserControl xmlns="https://github.com/avaloniaui" |
||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" |
||||
|
x:Class="ControlCatalog.Pages.CarouselPagePerformancePage"> |
||||
|
<Grid ColumnDefinitions="*,240"> |
||||
|
|
||||
|
<Border Grid.Column="0" Margin="12" |
||||
|
BorderBrush="{DynamicResource SystemControlForegroundBaseMediumLowBrush}" |
||||
|
BorderThickness="1" |
||||
|
CornerRadius="6" |
||||
|
ClipToBounds="True"> |
||||
|
<CarouselPage x:Name="DemoCarousel" /> |
||||
|
</Border> |
||||
|
|
||||
|
<Border Grid.Column="1" |
||||
|
BorderBrush="{DynamicResource SystemControlForegroundBaseMediumLowBrush}" |
||||
|
BorderThickness="1,0,0,0" Padding="12"> |
||||
|
<ScrollViewer> |
||||
|
<StackPanel Spacing="8"> |
||||
|
|
||||
|
<TextBlock Text="Actions" FontWeight="SemiBold" /> |
||||
|
<Button Content="Add 5 Pages" HorizontalAlignment="Stretch" Click="OnAdd5" /> |
||||
|
<Button Content="Add 20 Pages" HorizontalAlignment="Stretch" Click="OnAdd20" /> |
||||
|
<Button Content="Remove Last 5" HorizontalAlignment="Stretch" Click="OnRemove5" /> |
||||
|
<Button Content="Clear All" HorizontalAlignment="Stretch" Click="OnClearAll" /> |
||||
|
|
||||
|
<Separator /> |
||||
|
|
||||
|
<Button Content="Force GC" HorizontalAlignment="Stretch" Click="OnForceGC" /> |
||||
|
<Button Content="Refresh Stats" HorizontalAlignment="Stretch" Click="OnRefresh" /> |
||||
|
|
||||
|
<Separator /> |
||||
|
|
||||
|
<TextBlock Text="Statistics" FontWeight="SemiBold" /> |
||||
|
<TextBlock x:Name="PageCountText" Text="Page count: 0" FontSize="12" /> |
||||
|
<TextBlock x:Name="LiveCountText" Text="Live instances: 0" FontSize="12" /> |
||||
|
<TextBlock x:Name="HeapText" Text="Heap: 0 KB" FontSize="12" /> |
||||
|
<TextBlock x:Name="AllocText" Text="Total allocated: 0 KB" FontSize="12" /> |
||||
|
<TextBlock x:Name="LastOpTimeText" Text="Last Op: " FontSize="12" /> |
||||
|
|
||||
|
</StackPanel> |
||||
|
</ScrollViewer> |
||||
|
</Border> |
||||
|
|
||||
|
</Grid> |
||||
|
</UserControl> |
||||
@ -0,0 +1,103 @@ |
|||||
|
using System; |
||||
|
using System.Collections; |
||||
|
using Avalonia.Controls; |
||||
|
using Avalonia.Interactivity; |
||||
|
using Avalonia.Layout; |
||||
|
|
||||
|
namespace ControlCatalog.Pages |
||||
|
{ |
||||
|
public partial class CarouselPagePerformancePage : UserControl |
||||
|
{ |
||||
|
private readonly NavigationPerformanceMonitorHelper _perf = new(); |
||||
|
private int _counter; |
||||
|
|
||||
|
public CarouselPagePerformancePage() |
||||
|
{ |
||||
|
InitializeComponent(); |
||||
|
Loaded += OnLoaded; |
||||
|
Unloaded += OnUnloaded; |
||||
|
} |
||||
|
|
||||
|
private void OnLoaded(object? sender, RoutedEventArgs e) |
||||
|
{ |
||||
|
AddPages(5); |
||||
|
DemoCarousel.SelectionChanged += OnSelectionChanged; |
||||
|
} |
||||
|
|
||||
|
private void OnUnloaded(object? sender, RoutedEventArgs e) |
||||
|
{ |
||||
|
DemoCarousel.SelectionChanged -= OnSelectionChanged; |
||||
|
} |
||||
|
|
||||
|
private void OnSelectionChanged(object? sender, PageSelectionChangedEventArgs e) => RefreshStats(); |
||||
|
|
||||
|
private void AddPages(int count) |
||||
|
{ |
||||
|
var pages = (IList)DemoCarousel.Pages!; |
||||
|
_perf.OpStopwatch.Restart(); |
||||
|
for (int i = 0; i < count; i++) |
||||
|
{ |
||||
|
var idx = ++_counter; |
||||
|
var page = new ContentPage |
||||
|
{ |
||||
|
Header = $"P{idx}", |
||||
|
Content = new TextBlock |
||||
|
{ |
||||
|
Text = $"Page {idx}", |
||||
|
HorizontalAlignment = HorizontalAlignment.Center, |
||||
|
VerticalAlignment = VerticalAlignment.Center, |
||||
|
FontSize = 18, |
||||
|
Opacity = 0.7 |
||||
|
}, |
||||
|
Tag = new byte[51200], |
||||
|
}; |
||||
|
_perf.TrackPage(page); |
||||
|
pages.Add(page); |
||||
|
} |
||||
|
|
||||
|
_perf.StopMetrics(LastOpTimeText); |
||||
|
RefreshStats(); |
||||
|
} |
||||
|
|
||||
|
private void RemovePages(int count) |
||||
|
{ |
||||
|
var pages = (IList)DemoCarousel.Pages!; |
||||
|
_perf.OpStopwatch.Restart(); |
||||
|
for (int i = 0; i < count && pages.Count > 0; i++) |
||||
|
pages.RemoveAt(pages.Count - 1); |
||||
|
|
||||
|
_perf.StopMetrics(LastOpTimeText); |
||||
|
RefreshStats(); |
||||
|
} |
||||
|
|
||||
|
private void OnAdd5(object? sender, RoutedEventArgs e) => AddPages(5); |
||||
|
private void OnAdd20(object? sender, RoutedEventArgs e) => AddPages(20); |
||||
|
private void OnRemove5(object? sender, RoutedEventArgs e) => RemovePages(5); |
||||
|
|
||||
|
private void OnClearAll(object? sender, RoutedEventArgs e) |
||||
|
{ |
||||
|
var pages = (IList)DemoCarousel.Pages!; |
||||
|
_perf.OpStopwatch.Restart(); |
||||
|
while (pages.Count > 0) |
||||
|
pages.RemoveAt(pages.Count - 1); |
||||
|
_perf.StopMetrics(LastOpTimeText); |
||||
|
RefreshStats(); |
||||
|
} |
||||
|
|
||||
|
private void OnForceGC(object? sender, RoutedEventArgs e) |
||||
|
{ |
||||
|
_perf.ForceGC(RefreshStats); |
||||
|
} |
||||
|
|
||||
|
private void OnRefresh(object? sender, RoutedEventArgs e) => RefreshStats(); |
||||
|
|
||||
|
private void RefreshStats() |
||||
|
{ |
||||
|
var pages = (IList)DemoCarousel.Pages!; |
||||
|
PageCountText.Text = $"Page count: {pages.Count}"; |
||||
|
LiveCountText.Text = $"Live instances: {_perf.CountLiveInstances()} / {_perf.TotalCreated} tracked"; |
||||
|
HeapText.Text = $"Heap: {GC.GetTotalMemory(false) / 1024:N0} KB"; |
||||
|
AllocText.Text = $"Total allocated: {GC.GetTotalAllocatedBytes() / 1024:N0} KB"; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,90 @@ |
|||||
|
<UserControl xmlns="https://github.com/avaloniaui" |
||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" |
||||
|
x:Class="ControlCatalog.Pages.CarouselPageSelectionPage"> |
||||
|
<DockPanel> |
||||
|
<ScrollViewer DockPanel.Dock="Right" Width="220"> |
||||
|
<StackPanel Margin="12" Spacing="8"> |
||||
|
<TextBlock Text="Configuration" FontWeight="SemiBold" FontSize="16" |
||||
|
Foreground="{DynamicResource SystemControlHighlightAccentBrush}" /> |
||||
|
|
||||
|
<TextBlock Text="Jump to Page" FontWeight="SemiBold" FontSize="13" /> |
||||
|
<StackPanel Spacing="6"> |
||||
|
<Button Content="Go to Page 1" Click="OnGoTo0" HorizontalAlignment="Stretch" /> |
||||
|
<Button Content="Go to Page 2" Click="OnGoTo1" HorizontalAlignment="Stretch" /> |
||||
|
<Button Content="Go to Page 3" Click="OnGoTo2" HorizontalAlignment="Stretch" /> |
||||
|
<Button Content="Go to Page 4" Click="OnGoTo3" HorizontalAlignment="Stretch" /> |
||||
|
</StackPanel> |
||||
|
|
||||
|
<Separator /> |
||||
|
|
||||
|
<TextBlock Text="Navigate" FontWeight="SemiBold" FontSize="13" /> |
||||
|
<StackPanel Spacing="6"> |
||||
|
<Button Content="First" Click="OnFirst" HorizontalAlignment="Stretch" /> |
||||
|
<Button Content="Previous" Click="OnPrevious" HorizontalAlignment="Stretch" /> |
||||
|
<Button Content="Next" Click="OnNext" HorizontalAlignment="Stretch" /> |
||||
|
<Button Content="Last" Click="OnLast" HorizontalAlignment="Stretch" /> |
||||
|
</StackPanel> |
||||
|
|
||||
|
<Separator /> |
||||
|
|
||||
|
<TextBlock Text="Status" FontWeight="SemiBold" FontSize="13" /> |
||||
|
<TextBlock x:Name="StatusText" Text="—" Opacity="0.7" TextWrapping="Wrap" /> |
||||
|
</StackPanel> |
||||
|
</ScrollViewer> |
||||
|
|
||||
|
<Border DockPanel.Dock="Right" Width="1" |
||||
|
Background="{DynamicResource SystemControlForegroundBaseMediumLowBrush}" /> |
||||
|
|
||||
|
<Border Margin="12" |
||||
|
BorderBrush="{DynamicResource SystemControlForegroundBaseMediumLowBrush}" |
||||
|
BorderThickness="1" CornerRadius="6" ClipToBounds="True"> |
||||
|
<CarouselPage x:Name="DemoCarousel" |
||||
|
SelectionChanged="OnSelectionChanged"> |
||||
|
<ContentPage Header="Onboarding" Background="#BBDEFB"> |
||||
|
<StackPanel Margin="24" Spacing="8" |
||||
|
HorizontalAlignment="Center" VerticalAlignment="Center"> |
||||
|
<TextBlock Text="Step 1 of 4" FontSize="14" Opacity="0.6" |
||||
|
HorizontalAlignment="Center" /> |
||||
|
<TextBlock Text="Onboarding" FontSize="28" FontWeight="Bold" |
||||
|
HorizontalAlignment="Center" /> |
||||
|
<TextBlock Text="Set SelectedIndex to jump directly to any page." |
||||
|
TextWrapping="Wrap" Opacity="0.7" TextAlignment="Center" MaxWidth="260" /> |
||||
|
</StackPanel> |
||||
|
</ContentPage> |
||||
|
<ContentPage Header="Features" Background="#C8E6C9"> |
||||
|
<StackPanel Margin="24" Spacing="8" |
||||
|
HorizontalAlignment="Center" VerticalAlignment="Center"> |
||||
|
<TextBlock Text="Step 2 of 4" FontSize="14" Opacity="0.6" |
||||
|
HorizontalAlignment="Center" /> |
||||
|
<TextBlock Text="Features" FontSize="28" FontWeight="Bold" |
||||
|
HorizontalAlignment="Center" /> |
||||
|
<TextBlock Text="Supports scroll, transition, swipe gesture and keyboard navigation." |
||||
|
TextWrapping="Wrap" Opacity="0.7" TextAlignment="Center" MaxWidth="260" /> |
||||
|
</StackPanel> |
||||
|
</ContentPage> |
||||
|
<ContentPage Header="Customize" Background="#FFE0B2"> |
||||
|
<StackPanel Margin="24" Spacing="8" |
||||
|
HorizontalAlignment="Center" VerticalAlignment="Center"> |
||||
|
<TextBlock Text="Step 3 of 4" FontSize="14" Opacity="0.6" |
||||
|
HorizontalAlignment="Center" /> |
||||
|
<TextBlock Text="Customize" FontSize="28" FontWeight="Bold" |
||||
|
HorizontalAlignment="Center" /> |
||||
|
<TextBlock Text="Override the ItemsPanel, add any Avalonia Page as a child." |
||||
|
TextWrapping="Wrap" Opacity="0.7" TextAlignment="Center" MaxWidth="260" /> |
||||
|
</StackPanel> |
||||
|
</ContentPage> |
||||
|
<ContentPage Header="Ready" Background="#E1BEE7"> |
||||
|
<StackPanel Margin="24" Spacing="8" |
||||
|
HorizontalAlignment="Center" VerticalAlignment="Center"> |
||||
|
<TextBlock Text="Step 4 of 4" FontSize="14" Opacity="0.6" |
||||
|
HorizontalAlignment="Center" /> |
||||
|
<TextBlock Text="Ready!" FontSize="28" FontWeight="Bold" |
||||
|
HorizontalAlignment="Center" /> |
||||
|
<TextBlock Text="You are all set. Use SelectionChanged to react to navigation." |
||||
|
TextWrapping="Wrap" Opacity="0.7" TextAlignment="Center" MaxWidth="260" /> |
||||
|
</StackPanel> |
||||
|
</ContentPage> |
||||
|
</CarouselPage> |
||||
|
</Border> |
||||
|
</DockPanel> |
||||
|
</UserControl> |
||||
@ -0,0 +1,56 @@ |
|||||
|
using System.Collections; |
||||
|
using Avalonia.Controls; |
||||
|
using Avalonia.Interactivity; |
||||
|
|
||||
|
namespace ControlCatalog.Pages |
||||
|
{ |
||||
|
public partial class CarouselPageSelectionPage : UserControl |
||||
|
{ |
||||
|
public CarouselPageSelectionPage() |
||||
|
{ |
||||
|
InitializeComponent(); |
||||
|
Loaded += (_, _) => UpdateStatus(); |
||||
|
} |
||||
|
|
||||
|
private void OnGoTo0(object? sender, RoutedEventArgs e) => DemoCarousel.SelectedIndex = 0; |
||||
|
private void OnGoTo1(object? sender, RoutedEventArgs e) => DemoCarousel.SelectedIndex = 1; |
||||
|
private void OnGoTo2(object? sender, RoutedEventArgs e) => DemoCarousel.SelectedIndex = 2; |
||||
|
private void OnGoTo3(object? sender, RoutedEventArgs e) => DemoCarousel.SelectedIndex = 3; |
||||
|
|
||||
|
private void OnFirst(object? sender, RoutedEventArgs e) => DemoCarousel.SelectedIndex = 0; |
||||
|
|
||||
|
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 OnLast(object? sender, RoutedEventArgs e) |
||||
|
{ |
||||
|
var pageCount = (DemoCarousel.Pages as IList)?.Count ?? 0; |
||||
|
if (pageCount > 0) |
||||
|
DemoCarousel.SelectedIndex = pageCount - 1; |
||||
|
} |
||||
|
|
||||
|
private void OnSelectionChanged(object? sender, PageSelectionChangedEventArgs e) |
||||
|
{ |
||||
|
UpdateStatus(); |
||||
|
} |
||||
|
|
||||
|
private void UpdateStatus() |
||||
|
{ |
||||
|
if (StatusText == null) |
||||
|
return; |
||||
|
var pageCount = (DemoCarousel.Pages as IList)?.Count ?? 0; |
||||
|
var header = (DemoCarousel.SelectedPage as ContentPage)?.Header?.ToString() ?? "—"; |
||||
|
StatusText.Text = $"Page {DemoCarousel.SelectedIndex + 1} of {pageCount}: {header}"; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,65 @@ |
|||||
|
<UserControl xmlns="https://github.com/avaloniaui" |
||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" |
||||
|
x:Class="ControlCatalog.Pages.CarouselPageTransitionsPage"> |
||||
|
<DockPanel> |
||||
|
<ScrollViewer DockPanel.Dock="Right" Width="220"> |
||||
|
<StackPanel Margin="12" Spacing="8"> |
||||
|
<TextBlock Text="Configuration" FontWeight="SemiBold" FontSize="16" |
||||
|
Foreground="{DynamicResource SystemControlHighlightAccentBrush}" /> |
||||
|
|
||||
|
<TextBlock Text="Page Transition" FontWeight="SemiBold" FontSize="13" /> |
||||
|
<ComboBox x:Name="TransitionCombo" SelectedIndex="0" |
||||
|
SelectionChanged="OnTransitionChanged" |
||||
|
HorizontalAlignment="Stretch"> |
||||
|
<ComboBoxItem Content="None" /> |
||||
|
<ComboBoxItem Content="CrossFade" /> |
||||
|
<ComboBoxItem Content="Slide Horizontal" /> |
||||
|
<ComboBoxItem Content="Slide Vertical" /> |
||||
|
<ComboBoxItem Content="Card Stack" /> |
||||
|
<ComboBoxItem Content="Wave Reveal" /> |
||||
|
</ComboBox> |
||||
|
|
||||
|
<Separator /> |
||||
|
|
||||
|
<TextBlock Text="Navigate" FontWeight="SemiBold" FontSize="13" /> |
||||
|
<StackPanel Spacing="6"> |
||||
|
<Button Content="Previous" Click="OnPrevious" HorizontalAlignment="Stretch" /> |
||||
|
<Button Content="Next" Click="OnNext" HorizontalAlignment="Stretch" /> |
||||
|
</StackPanel> |
||||
|
|
||||
|
<Separator /> |
||||
|
|
||||
|
<TextBlock Text="Status" FontWeight="SemiBold" FontSize="13" /> |
||||
|
<TextBlock x:Name="StatusText" Text="Page 1 of 4 | Transition: None" |
||||
|
Opacity="0.7" TextWrapping="Wrap" /> |
||||
|
</StackPanel> |
||||
|
</ScrollViewer> |
||||
|
|
||||
|
<Border DockPanel.Dock="Right" Width="1" |
||||
|
Background="{DynamicResource SystemControlForegroundBaseMediumLowBrush}" /> |
||||
|
|
||||
|
<Border Margin="12" |
||||
|
BorderBrush="{DynamicResource SystemControlForegroundBaseMediumLowBrush}" |
||||
|
BorderThickness="1" CornerRadius="6" ClipToBounds="True"> |
||||
|
<CarouselPage x:Name="DemoCarousel" |
||||
|
SelectionChanged="OnSelectionChanged"> |
||||
|
<ContentPage Header="Page 1" Background="#BBDEFB"> |
||||
|
<TextBlock Text="Page 1" FontSize="32" FontWeight="Bold" |
||||
|
HorizontalAlignment="Center" VerticalAlignment="Center" /> |
||||
|
</ContentPage> |
||||
|
<ContentPage Header="Page 2" Background="#C8E6C9"> |
||||
|
<TextBlock Text="Page 2" FontSize="32" FontWeight="Bold" |
||||
|
HorizontalAlignment="Center" VerticalAlignment="Center" /> |
||||
|
</ContentPage> |
||||
|
<ContentPage Header="Page 3" Background="#FFE0B2"> |
||||
|
<TextBlock Text="Page 3" FontSize="32" FontWeight="Bold" |
||||
|
HorizontalAlignment="Center" VerticalAlignment="Center" /> |
||||
|
</ContentPage> |
||||
|
<ContentPage Header="Page 4" Background="#E1BEE7"> |
||||
|
<TextBlock Text="Page 4" FontSize="32" FontWeight="Bold" |
||||
|
HorizontalAlignment="Center" VerticalAlignment="Center" /> |
||||
|
</ContentPage> |
||||
|
</CarouselPage> |
||||
|
</Border> |
||||
|
</DockPanel> |
||||
|
</UserControl> |
||||
@ -0,0 +1,69 @@ |
|||||
|
using System; |
||||
|
using System.Collections; |
||||
|
using Avalonia.Animation; |
||||
|
using Avalonia.Controls; |
||||
|
using Avalonia.Interactivity; |
||||
|
using ControlCatalog.Pages.Transitions; |
||||
|
|
||||
|
namespace ControlCatalog.Pages |
||||
|
{ |
||||
|
public partial class CarouselPageTransitionsPage : UserControl |
||||
|
{ |
||||
|
public CarouselPageTransitionsPage() |
||||
|
{ |
||||
|
InitializeComponent(); |
||||
|
} |
||||
|
|
||||
|
private void OnTransitionChanged(object? sender, SelectionChangedEventArgs e) |
||||
|
{ |
||||
|
if (DemoCarousel == null) |
||||
|
return; |
||||
|
|
||||
|
DemoCarousel.PageTransition = TransitionCombo?.SelectedIndex switch |
||||
|
{ |
||||
|
0 => null, |
||||
|
1 => new CrossFade(TimeSpan.FromMilliseconds(300)), |
||||
|
2 => new PageSlide(TimeSpan.FromMilliseconds(300), PageSlide.SlideAxis.Horizontal), |
||||
|
3 => new PageSlide(TimeSpan.FromMilliseconds(300), PageSlide.SlideAxis.Vertical), |
||||
|
4 => new CardStackPageTransition(TimeSpan.FromMilliseconds(400)), |
||||
|
5 => new WaveRevealPageTransition(TimeSpan.FromMilliseconds(600)), |
||||
|
_ => null |
||||
|
}; |
||||
|
|
||||
|
UpdateStatus(); |
||||
|
} |
||||
|
|
||||
|
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) |
||||
|
{ |
||||
|
UpdateStatus(); |
||||
|
} |
||||
|
|
||||
|
private void UpdateStatus() |
||||
|
{ |
||||
|
if (StatusText == null) |
||||
|
return; |
||||
|
var pageCount = (DemoCarousel.Pages as IList)?.Count ?? 0; |
||||
|
var modeName = DemoCarousel.PageTransition switch |
||||
|
{ |
||||
|
null => "None", |
||||
|
CardStackPageTransition => "Card Stack", |
||||
|
WaveRevealPageTransition => "Wave Reveal", |
||||
|
{ } t => t.GetType().Name |
||||
|
}; |
||||
|
StatusText.Text = $"Page {DemoCarousel.SelectedIndex + 1} of {pageCount} | Transition: {modeName}"; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,97 @@ |
|||||
|
<UserControl xmlns="https://github.com/avaloniaui" |
||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" |
||||
|
x:Class="ControlCatalog.Pages.CarouselTransitionsPage"> |
||||
|
<DockPanel> |
||||
|
<ScrollViewer DockPanel.Dock="Right" Width="260"> |
||||
|
<StackPanel Margin="12" Spacing="8"> |
||||
|
<TextBlock Text="Configuration" FontWeight="SemiBold" FontSize="16" |
||||
|
Foreground="{DynamicResource SystemControlHighlightAccentBrush}" /> |
||||
|
|
||||
|
<TextBlock Text="Navigation" FontWeight="SemiBold" FontSize="13" /> |
||||
|
|
||||
|
<Button x:Name="PreviousButton" |
||||
|
Content="Previous" |
||||
|
HorizontalAlignment="Stretch" /> |
||||
|
<Button x:Name="NextButton" |
||||
|
Content="Next" |
||||
|
HorizontalAlignment="Stretch" /> |
||||
|
|
||||
|
<Separator /> |
||||
|
|
||||
|
<TextBlock Text="Transition" FontWeight="SemiBold" FontSize="13" /> |
||||
|
<ComboBox x:Name="TransitionCombo" |
||||
|
HorizontalAlignment="Stretch" |
||||
|
SelectedIndex="1"> |
||||
|
<ComboBoxItem>None</ComboBoxItem> |
||||
|
<ComboBoxItem>Page Slide</ComboBoxItem> |
||||
|
<ComboBoxItem>Cross Fade</ComboBoxItem> |
||||
|
<ComboBoxItem>Rotate 3D</ComboBoxItem> |
||||
|
<ComboBoxItem>Card Stack</ComboBoxItem> |
||||
|
<ComboBoxItem>Wave Reveal</ComboBoxItem> |
||||
|
<ComboBoxItem>Composite (Slide + Fade)</ComboBoxItem> |
||||
|
</ComboBox> |
||||
|
|
||||
|
<TextBlock Text="Orientation" FontWeight="SemiBold" FontSize="13" /> |
||||
|
<ComboBox x:Name="OrientationCombo" |
||||
|
HorizontalAlignment="Stretch" |
||||
|
SelectedIndex="0"> |
||||
|
<ComboBoxItem>Horizontal</ComboBoxItem> |
||||
|
<ComboBoxItem>Vertical</ComboBoxItem> |
||||
|
</ComboBox> |
||||
|
|
||||
|
<Separator /> |
||||
|
|
||||
|
<TextBlock Text="Status" FontWeight="SemiBold" FontSize="14" /> |
||||
|
<TextBlock x:Name="StatusText" |
||||
|
Text="Transition: Page Slide" |
||||
|
Opacity="0.7" |
||||
|
TextWrapping="Wrap" /> |
||||
|
</StackPanel> |
||||
|
</ScrollViewer> |
||||
|
|
||||
|
<Border DockPanel.Dock="Right" Width="1" |
||||
|
Background="{DynamicResource SystemControlForegroundBaseMediumLowBrush}" /> |
||||
|
|
||||
|
<Border Margin="12" |
||||
|
BorderBrush="{DynamicResource SystemControlForegroundBaseMediumLowBrush}" |
||||
|
BorderThickness="1" |
||||
|
CornerRadius="6" |
||||
|
ClipToBounds="True"> |
||||
|
<Carousel x:Name="DemoCarousel" Height="300"> |
||||
|
<Carousel.PageTransition> |
||||
|
<PageSlide Duration="0.25" Orientation="Horizontal" /> |
||||
|
</Carousel.PageTransition> |
||||
|
|
||||
|
<Border Margin="14,12" CornerRadius="12" ClipToBounds="True"> |
||||
|
<Grid> |
||||
|
<Image Source="/Assets/delicate-arch-896885_640.jpg" Stretch="UniformToFill" /> |
||||
|
<Border Background="#80000000" VerticalAlignment="Bottom" Padding="12"> |
||||
|
<TextBlock Text="Item 1: Delicate Arch" Foreground="White" |
||||
|
HorizontalAlignment="Center" FontWeight="SemiBold" /> |
||||
|
</Border> |
||||
|
</Grid> |
||||
|
</Border> |
||||
|
|
||||
|
<Border Margin="14,12" CornerRadius="12" ClipToBounds="True"> |
||||
|
<Grid> |
||||
|
<Image Source="/Assets/hirsch-899118_640.jpg" Stretch="UniformToFill" /> |
||||
|
<Border Background="#80000000" VerticalAlignment="Bottom" Padding="12"> |
||||
|
<TextBlock Text="Item 2: Hirsch" Foreground="White" |
||||
|
HorizontalAlignment="Center" FontWeight="SemiBold" /> |
||||
|
</Border> |
||||
|
</Grid> |
||||
|
</Border> |
||||
|
|
||||
|
<Border Margin="14,12" CornerRadius="12" ClipToBounds="True"> |
||||
|
<Grid> |
||||
|
<Image Source="/Assets/maple-leaf-888807_640.jpg" Stretch="UniformToFill" /> |
||||
|
<Border Background="#80000000" VerticalAlignment="Bottom" Padding="12"> |
||||
|
<TextBlock Text="Item 3: Maple Leaf" Foreground="White" |
||||
|
HorizontalAlignment="Center" FontWeight="SemiBold" /> |
||||
|
</Border> |
||||
|
</Grid> |
||||
|
</Border> |
||||
|
</Carousel> |
||||
|
</Border> |
||||
|
</DockPanel> |
||||
|
</UserControl> |
||||
@ -0,0 +1,66 @@ |
|||||
|
using System; |
||||
|
using Avalonia.Animation; |
||||
|
using Avalonia.Controls; |
||||
|
using ControlCatalog.Pages.Transitions; |
||||
|
|
||||
|
namespace ControlCatalog.Pages |
||||
|
{ |
||||
|
public partial class CarouselTransitionsPage : UserControl |
||||
|
{ |
||||
|
public CarouselTransitionsPage() |
||||
|
{ |
||||
|
InitializeComponent(); |
||||
|
PreviousButton.Click += (_, _) => DemoCarousel.Previous(); |
||||
|
NextButton.Click += (_, _) => DemoCarousel.Next(); |
||||
|
TransitionCombo.SelectionChanged += (_, _) => ApplyTransition(); |
||||
|
OrientationCombo.SelectionChanged += (_, _) => ApplyTransition(); |
||||
|
} |
||||
|
|
||||
|
private void ApplyTransition() |
||||
|
{ |
||||
|
var axis = OrientationCombo.SelectedIndex == 0 ? |
||||
|
PageSlide.SlideAxis.Horizontal : |
||||
|
PageSlide.SlideAxis.Vertical; |
||||
|
var label = axis == PageSlide.SlideAxis.Horizontal ? "Horizontal" : "Vertical"; |
||||
|
|
||||
|
switch (TransitionCombo.SelectedIndex) |
||||
|
{ |
||||
|
case 0: |
||||
|
DemoCarousel.PageTransition = null; |
||||
|
StatusText.Text = "Transition: None"; |
||||
|
break; |
||||
|
case 1: |
||||
|
DemoCarousel.PageTransition = new PageSlide(TimeSpan.FromSeconds(0.25), axis); |
||||
|
StatusText.Text = $"Transition: Page Slide ({label})"; |
||||
|
break; |
||||
|
case 2: |
||||
|
DemoCarousel.PageTransition = new CrossFade(TimeSpan.FromSeconds(0.25)); |
||||
|
StatusText.Text = "Transition: Cross Fade"; |
||||
|
break; |
||||
|
case 3: |
||||
|
DemoCarousel.PageTransition = new Rotate3DTransition(TimeSpan.FromSeconds(0.5), axis); |
||||
|
StatusText.Text = $"Transition: Rotate 3D ({label})"; |
||||
|
break; |
||||
|
case 4: |
||||
|
DemoCarousel.PageTransition = new CardStackPageTransition(TimeSpan.FromSeconds(0.5), axis); |
||||
|
StatusText.Text = $"Transition: Card Stack ({label})"; |
||||
|
break; |
||||
|
case 5: |
||||
|
DemoCarousel.PageTransition = new WaveRevealPageTransition(TimeSpan.FromSeconds(0.8), axis); |
||||
|
StatusText.Text = $"Transition: Wave Reveal ({label})"; |
||||
|
break; |
||||
|
case 6: |
||||
|
DemoCarousel.PageTransition = new CompositePageTransition |
||||
|
{ |
||||
|
PageTransitions = |
||||
|
{ |
||||
|
new PageSlide(TimeSpan.FromSeconds(0.25), axis), |
||||
|
new CrossFade(TimeSpan.FromSeconds(0.25)), |
||||
|
} |
||||
|
}; |
||||
|
StatusText.Text = "Transition: Composite (Slide + Fade)"; |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,132 @@ |
|||||
|
<UserControl xmlns="https://github.com/avaloniaui" |
||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" |
||||
|
x:Class="ControlCatalog.Pages.CarouselVerticalPage"> |
||||
|
<DockPanel> |
||||
|
<ScrollViewer DockPanel.Dock="Right" Width="260"> |
||||
|
<StackPanel Margin="12" Spacing="8"> |
||||
|
<TextBlock Text="Configuration" FontWeight="SemiBold" FontSize="16" |
||||
|
Foreground="{DynamicResource SystemControlHighlightAccentBrush}" /> |
||||
|
|
||||
|
<TextBlock Text="Navigation" FontWeight="SemiBold" FontSize="13" /> |
||||
|
<Button x:Name="PreviousButton" Content="Up" HorizontalAlignment="Stretch" /> |
||||
|
<Button x:Name="NextButton" Content="Down" HorizontalAlignment="Stretch" /> |
||||
|
|
||||
|
<Separator /> |
||||
|
|
||||
|
<TextBlock Text="Transition" FontWeight="SemiBold" FontSize="13" /> |
||||
|
<ComboBox x:Name="TransitionCombo" |
||||
|
HorizontalAlignment="Stretch" |
||||
|
SelectedIndex="0"> |
||||
|
<ComboBoxItem>PageSlide</ComboBoxItem> |
||||
|
<ComboBoxItem>CrossFade</ComboBoxItem> |
||||
|
<ComboBoxItem>None</ComboBoxItem> |
||||
|
</ComboBox> |
||||
|
|
||||
|
<Separator /> |
||||
|
|
||||
|
<TextBlock Text="Options" FontWeight="SemiBold" FontSize="13" /> |
||||
|
<CheckBox x:Name="WrapCheck" |
||||
|
Content="Wrap Selection" |
||||
|
IsChecked="False" |
||||
|
IsCheckedChanged="OnWrapSelectionChanged" /> |
||||
|
|
||||
|
<Separator /> |
||||
|
|
||||
|
<TextBlock Text="Status" FontWeight="SemiBold" FontSize="14" /> |
||||
|
<TextBlock x:Name="StatusText" |
||||
|
Text="Item: 1 / 4" |
||||
|
Opacity="0.7" |
||||
|
TextWrapping="Wrap" /> |
||||
|
<TextBlock Text="Use Up/Down arrow keys or buttons to navigate." |
||||
|
FontSize="11" |
||||
|
Opacity="0.5" |
||||
|
TextWrapping="Wrap" /> |
||||
|
</StackPanel> |
||||
|
</ScrollViewer> |
||||
|
|
||||
|
<Border DockPanel.Dock="Right" Width="1" |
||||
|
Background="{DynamicResource SystemControlForegroundBaseMediumLowBrush}" /> |
||||
|
|
||||
|
<Border Margin="12" |
||||
|
BorderBrush="{DynamicResource SystemControlForegroundBaseMediumLowBrush}" |
||||
|
BorderThickness="1" |
||||
|
CornerRadius="6" |
||||
|
ClipToBounds="True"> |
||||
|
<Carousel x:Name="DemoCarousel" |
||||
|
Focusable="True" |
||||
|
IsSwipeEnabled="True"> |
||||
|
<Carousel.PageTransition> |
||||
|
<PageSlide Duration="0.3" Orientation="Vertical" /> |
||||
|
</Carousel.PageTransition> |
||||
|
|
||||
|
<Border Margin="14,12" CornerRadius="12"> |
||||
|
<Border.Background> |
||||
|
<LinearGradientBrush StartPoint="0%,0%" EndPoint="100%,100%"> |
||||
|
<GradientStop Color="#1A1A2E" Offset="0" /> |
||||
|
<GradientStop Color="#3525CD" Offset="1" /> |
||||
|
</LinearGradientBrush> |
||||
|
</Border.Background> |
||||
|
<StackPanel VerticalAlignment="Center" HorizontalAlignment="Center" Spacing="10"> |
||||
|
<TextBlock Text="01" FontSize="64" FontWeight="Bold" |
||||
|
Foreground="White" HorizontalAlignment="Center" LetterSpacing="-2" /> |
||||
|
<TextBlock Text="Neon Pulse" FontSize="18" FontWeight="SemiBold" |
||||
|
Foreground="#C3C0FF" HorizontalAlignment="Center" /> |
||||
|
<TextBlock Text="Slide down to explore" FontSize="12" |
||||
|
Foreground="#80FFFFFF" HorizontalAlignment="Center" /> |
||||
|
</StackPanel> |
||||
|
</Border> |
||||
|
|
||||
|
<Border Margin="14,12" CornerRadius="12"> |
||||
|
<Border.Background> |
||||
|
<LinearGradientBrush StartPoint="0%,0%" EndPoint="100%,100%"> |
||||
|
<GradientStop Color="#0C1A1F" Offset="0" /> |
||||
|
<GradientStop Color="#0891B2" Offset="1" /> |
||||
|
</LinearGradientBrush> |
||||
|
</Border.Background> |
||||
|
<StackPanel VerticalAlignment="Center" HorizontalAlignment="Center" Spacing="10"> |
||||
|
<TextBlock Text="02" FontSize="64" FontWeight="Bold" |
||||
|
Foreground="White" HorizontalAlignment="Center" LetterSpacing="-2" /> |
||||
|
<TextBlock Text="Ephemeral Blue" FontSize="18" FontWeight="SemiBold" |
||||
|
Foreground="#BAF0FA" HorizontalAlignment="Center" /> |
||||
|
<TextBlock Text="Vertical PageSlide in action" FontSize="12" |
||||
|
Foreground="#80FFFFFF" HorizontalAlignment="Center" /> |
||||
|
</StackPanel> |
||||
|
</Border> |
||||
|
|
||||
|
<Border Margin="14,12" CornerRadius="12"> |
||||
|
<Border.Background> |
||||
|
<LinearGradientBrush StartPoint="0%,0%" EndPoint="100%,100%"> |
||||
|
<GradientStop Color="#0A1F18" Offset="0" /> |
||||
|
<GradientStop Color="#059669" Offset="1" /> |
||||
|
</LinearGradientBrush> |
||||
|
</Border.Background> |
||||
|
<StackPanel VerticalAlignment="Center" HorizontalAlignment="Center" Spacing="10"> |
||||
|
<TextBlock Text="03" FontSize="64" FontWeight="Bold" |
||||
|
Foreground="White" HorizontalAlignment="Center" LetterSpacing="-2" /> |
||||
|
<TextBlock Text="Forest Forms" FontSize="18" FontWeight="SemiBold" |
||||
|
Foreground="#A7F3D0" HorizontalAlignment="Center" /> |
||||
|
<TextBlock Text="Swipe up or down on touch screens" FontSize="12" |
||||
|
Foreground="#80FFFFFF" HorizontalAlignment="Center" /> |
||||
|
</StackPanel> |
||||
|
</Border> |
||||
|
|
||||
|
<Border Margin="14,12" CornerRadius="12"> |
||||
|
<Border.Background> |
||||
|
<LinearGradientBrush StartPoint="0%,0%" EndPoint="100%,100%"> |
||||
|
<GradientStop Color="#1F1208" Offset="0" /> |
||||
|
<GradientStop Color="#D97706" Offset="1" /> |
||||
|
</LinearGradientBrush> |
||||
|
</Border.Background> |
||||
|
<StackPanel VerticalAlignment="Center" HorizontalAlignment="Center" Spacing="10"> |
||||
|
<TextBlock Text="04" FontSize="64" FontWeight="Bold" |
||||
|
Foreground="White" HorizontalAlignment="Center" LetterSpacing="-2" /> |
||||
|
<TextBlock Text="Golden Hour" FontSize="18" FontWeight="SemiBold" |
||||
|
Foreground="#FDE68A" HorizontalAlignment="Center" /> |
||||
|
<TextBlock Text="Switch transitions in the panel" FontSize="12" |
||||
|
Foreground="#80FFFFFF" HorizontalAlignment="Center" /> |
||||
|
</StackPanel> |
||||
|
</Border> |
||||
|
</Carousel> |
||||
|
</Border> |
||||
|
</DockPanel> |
||||
|
</UserControl> |
||||
@ -0,0 +1,39 @@ |
|||||
|
using Avalonia.Animation; |
||||
|
using Avalonia.Controls; |
||||
|
using Avalonia.Interactivity; |
||||
|
|
||||
|
namespace ControlCatalog.Pages |
||||
|
{ |
||||
|
public partial class CarouselVerticalPage : UserControl |
||||
|
{ |
||||
|
public CarouselVerticalPage() |
||||
|
{ |
||||
|
InitializeComponent(); |
||||
|
PreviousButton.Click += (_, _) => DemoCarousel.Previous(); |
||||
|
NextButton.Click += (_, _) => DemoCarousel.Next(); |
||||
|
DemoCarousel.SelectionChanged += OnSelectionChanged; |
||||
|
TransitionCombo.SelectionChanged += OnTransitionChanged; |
||||
|
DemoCarousel.Loaded += (_, _) => DemoCarousel.Focus(); |
||||
|
} |
||||
|
|
||||
|
private void OnSelectionChanged(object? sender, SelectionChangedEventArgs e) |
||||
|
{ |
||||
|
StatusText.Text = $"Item: {DemoCarousel.SelectedIndex + 1} / {DemoCarousel.ItemCount}"; |
||||
|
} |
||||
|
|
||||
|
private void OnTransitionChanged(object? sender, SelectionChangedEventArgs e) |
||||
|
{ |
||||
|
DemoCarousel.PageTransition = TransitionCombo.SelectedIndex switch |
||||
|
{ |
||||
|
1 => new CrossFade(System.TimeSpan.FromSeconds(0.3)), |
||||
|
2 => null, |
||||
|
_ => new PageSlide(System.TimeSpan.FromSeconds(0.3), PageSlide.SlideAxis.Vertical), |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
private void OnWrapSelectionChanged(object? sender, RoutedEventArgs e) |
||||
|
{ |
||||
|
DemoCarousel.WrapSelection = WrapCheck.IsChecked == true; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,298 @@ |
|||||
|
<UserControl xmlns="https://github.com/avaloniaui" |
||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" |
||||
|
x:Class="ControlCatalog.Pages.SanctuaryMainPage"> |
||||
|
<UserControl.Styles> |
||||
|
<Style Selector="Button.primary /template/ ContentPresenter#PART_ContentPresenter"> |
||||
|
<Setter Property="Background" Value="#f47b25" /> |
||||
|
<Setter Property="CornerRadius" Value="{TemplateBinding CornerRadius}" /> |
||||
|
</Style> |
||||
|
<Style Selector="Button.primary:pointerover /template/ ContentPresenter#PART_ContentPresenter"> |
||||
|
<Setter Property="Background" Value="#e0701f" /> |
||||
|
</Style> |
||||
|
<Style Selector="Button.primary:pressed /template/ ContentPresenter#PART_ContentPresenter"> |
||||
|
<Setter Property="Background" Value="#c9611a" /> |
||||
|
</Style> |
||||
|
<Style Selector="Button.glass /template/ ContentPresenter#PART_ContentPresenter"> |
||||
|
<Setter Property="Background" Value="#18FFFFFF" /> |
||||
|
<Setter Property="CornerRadius" Value="{TemplateBinding CornerRadius}" /> |
||||
|
</Style> |
||||
|
<Style Selector="Button.glass:pointerover /template/ ContentPresenter#PART_ContentPresenter"> |
||||
|
<Setter Property="Background" Value="#2AFFFFFF" /> |
||||
|
</Style> |
||||
|
<Style Selector="Button.glass:pressed /template/ ContentPresenter#PART_ContentPresenter"> |
||||
|
<Setter Property="Background" Value="#10FFFFFF" /> |
||||
|
</Style> |
||||
|
</UserControl.Styles> |
||||
|
|
||||
|
<DockPanel> |
||||
|
|
||||
|
<ScrollViewer DockPanel.Dock="Right" Width="220"> |
||||
|
<StackPanel Margin="12" Spacing="8"> |
||||
|
<TextBlock Text="Sanctuary" FontSize="16" FontWeight="SemiBold" |
||||
|
Foreground="{DynamicResource SystemControlHighlightAccentBrush}" /> |
||||
|
<TextBlock TextWrapping="Wrap" FontSize="12" Opacity="0.7" |
||||
|
Text="Main landing page with a full-screen hero card, Featured Escapes section, and a bottom TabbedPage navigation. Navigated to from the onboarding carousel." /> |
||||
|
<Separator /> |
||||
|
<TextBlock Text="Design" FontSize="13" FontWeight="SemiBold" /> |
||||
|
<TextBlock FontSize="12" Text="Theme: Dark (#221710)" /> |
||||
|
<TextBlock FontSize="12" Text="Primary: #f47b25 (warm orange)" /> |
||||
|
<Separator /> |
||||
|
<TextBlock Text="Tabs" FontSize="13" FontWeight="SemiBold" /> |
||||
|
<TextBlock FontSize="12" TextWrapping="Wrap" Text="Home — hero + Featured Escapes cards" /> |
||||
|
<TextBlock FontSize="12" TextWrapping="Wrap" Text="Explore — destination discovery" /> |
||||
|
<TextBlock FontSize="12" TextWrapping="Wrap" Text="Saved — bookmarked destinations" /> |
||||
|
<TextBlock FontSize="12" TextWrapping="Wrap" Text="Profile — account and settings" /> |
||||
|
<Separator /> |
||||
|
<TextBlock Text="Navigation" FontSize="13" FontWeight="SemiBold" /> |
||||
|
<TextBlock FontSize="12" TextWrapping="Wrap" Text="Reached via 'Get Started' on the Urban Adventures carousel page. Back stack is cleared on arrival." /> |
||||
|
</StackPanel> |
||||
|
</ScrollViewer> |
||||
|
|
||||
|
<Border DockPanel.Dock="Right" Width="1" |
||||
|
Background="{DynamicResource SystemControlForegroundBaseMediumLowBrush}" /> |
||||
|
|
||||
|
<Grid RowDefinitions="Auto,*" Background="#221710"> |
||||
|
|
||||
|
<!-- Top Nav Bar --> |
||||
|
<Border Grid.Row="0" Background="#DD221710" Padding="16,10,16,10"> |
||||
|
<Grid ColumnDefinitions="*,Auto"> |
||||
|
<StackPanel Grid.Column="0" Orientation="Horizontal" Spacing="8" VerticalAlignment="Center"> |
||||
|
<Panel Width="30" Height="30"> |
||||
|
<Ellipse Fill="#f47b25" /> |
||||
|
<TextBlock Text="▲" Foreground="White" FontSize="13" FontWeight="Bold" |
||||
|
HorizontalAlignment="Center" VerticalAlignment="Center" /> |
||||
|
</Panel> |
||||
|
<TextBlock Text="Sanctuary" FontSize="18" FontWeight="Bold" |
||||
|
Foreground="White" VerticalAlignment="Center" /> |
||||
|
</StackPanel> |
||||
|
<StackPanel Grid.Column="1" Orientation="Horizontal" Spacing="6" VerticalAlignment="Center"> |
||||
|
<Border Width="48" Height="48" CornerRadius="24" Background="#18FFFFFF"> |
||||
|
<TextBlock Text="⌕" FontSize="20" Foreground="#80FFFFFF" |
||||
|
HorizontalAlignment="Center" VerticalAlignment="Center" /> |
||||
|
</Border> |
||||
|
<Border Width="48" Height="48" CornerRadius="24" Background="#33f47b25"> |
||||
|
<TextBlock Text="◉" FontSize="19" Foreground="#f47b25" |
||||
|
HorizontalAlignment="Center" VerticalAlignment="Center" /> |
||||
|
</Border> |
||||
|
</StackPanel> |
||||
|
</Grid> |
||||
|
</Border> |
||||
|
|
||||
|
<!-- Tabbed content --> |
||||
|
<TabbedPage Grid.Row="1" |
||||
|
TabPlacement="Bottom" |
||||
|
SelectedIndex="0"> |
||||
|
<TabbedPage.Resources> |
||||
|
<SolidColorBrush x:Key="TabbedPageTabStripBackground">#221710</SolidColorBrush> |
||||
|
<SolidColorBrush x:Key="TabbedPageTabItemHeaderForegroundSelected">#f47b25</SolidColorBrush> |
||||
|
<SolidColorBrush x:Key="TabbedPageTabItemHeaderForegroundUnselected">#50FFFFFF</SolidColorBrush> |
||||
|
<Thickness x:Key="TabbedPageTabItemHeaderPadding">8,10,8,4</Thickness> |
||||
|
</TabbedPage.Resources> |
||||
|
|
||||
|
<!-- Home Tab --> |
||||
|
<ContentPage Header="Home" |
||||
|
Background="#221710"> |
||||
|
<ContentPage.Icon> |
||||
|
<StreamGeometry>M10 20v-6h4v6h5v-8h3L12 3 2 12h3v8z</StreamGeometry> |
||||
|
</ContentPage.Icon> |
||||
|
<ScrollViewer HorizontalScrollBarVisibility="Disabled" |
||||
|
VerticalScrollBarVisibility="Hidden"> |
||||
|
<StackPanel> |
||||
|
|
||||
|
<!-- Hero Card --> |
||||
|
<Border Margin="12,12,12,8" CornerRadius="16" ClipToBounds="True" Height="380"> |
||||
|
<Border.Background> |
||||
|
<ImageBrush Source="avares://ControlCatalog/Assets/Sanctuary/main_hero.jpg" |
||||
|
Stretch="UniformToFill" /> |
||||
|
</Border.Background> |
||||
|
<Grid> |
||||
|
<Border ClipToBounds="True" Margin="-1"> |
||||
|
<Border.Background> |
||||
|
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1"> |
||||
|
<GradientStop Offset="0" Color="Transparent" /> |
||||
|
<GradientStop Offset="0.45" Color="#55221710" /> |
||||
|
<GradientStop Offset="1" Color="#EE221710" /> |
||||
|
</LinearGradientBrush> |
||||
|
</Border.Background> |
||||
|
</Border> |
||||
|
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Bottom" |
||||
|
Margin="28,0,28,32" Spacing="14"> |
||||
|
<StackPanel HorizontalAlignment="Center" Spacing="2"> |
||||
|
<TextBlock Text="Find Your" FontSize="40" FontWeight="ExtraBold" |
||||
|
Foreground="White" TextAlignment="Center" /> |
||||
|
<TextBlock Text="Sanctuary" FontSize="40" FontWeight="ExtraBold" |
||||
|
Foreground="#f47b25" TextAlignment="Center" /> |
||||
|
</StackPanel> |
||||
|
<TextBlock Text="Embark on a curated journey through the world's most serene and breathtaking natural wonders. Escape the noise and rediscover peace." |
||||
|
FontSize="13" Foreground="#CAffffff" |
||||
|
TextAlignment="Center" TextWrapping="Wrap" MaxWidth="280" /> |
||||
|
<StackPanel Spacing="10" HorizontalAlignment="Center"> |
||||
|
<Button Classes="primary" |
||||
|
Foreground="#221710" FontWeight="Bold" FontSize="14" |
||||
|
CornerRadius="24" Padding="28,14" |
||||
|
HorizontalAlignment="Stretch" |
||||
|
HorizontalContentAlignment="Center"> |
||||
|
<TextBlock Text="Explore the Collection" Foreground="#221710" FontWeight="Bold" /> |
||||
|
</Button> |
||||
|
<Button Classes="glass" |
||||
|
Foreground="White" FontWeight="Bold" FontSize="14" |
||||
|
CornerRadius="24" Padding="28,14" |
||||
|
HorizontalAlignment="Stretch" |
||||
|
HorizontalContentAlignment="Center"> |
||||
|
<StackPanel Orientation="Horizontal" Spacing="8" HorizontalAlignment="Center"> |
||||
|
<TextBlock Text="⊕" Foreground="White" VerticalAlignment="Center" /> |
||||
|
<TextBlock Text="View Map" Foreground="White" FontWeight="Bold" VerticalAlignment="Center" /> |
||||
|
</StackPanel> |
||||
|
</Button> |
||||
|
</StackPanel> |
||||
|
</StackPanel> |
||||
|
</Grid> |
||||
|
</Border> |
||||
|
|
||||
|
<!-- Featured Escapes Header --> |
||||
|
<Grid Margin="16,8,16,12" ColumnDefinitions="*,Auto"> |
||||
|
<StackPanel Grid.Column="0" Spacing="3"> |
||||
|
<TextBlock Text="Featured Escapes" FontSize="20" FontWeight="Bold" Foreground="White" /> |
||||
|
<TextBlock Text="Hand-picked destinations for your next retreat" |
||||
|
FontSize="12" Foreground="#80FFFFFF" /> |
||||
|
</StackPanel> |
||||
|
<TextBlock Grid.Column="1" Text="See All" FontSize="12" FontWeight="Bold" |
||||
|
Foreground="#f47b25" VerticalAlignment="Bottom" /> |
||||
|
</Grid> |
||||
|
|
||||
|
<!-- Card 1: Deep Forest --> |
||||
|
<Border Margin="16,0,16,12" CornerRadius="16" ClipToBounds="True" Height="240"> |
||||
|
<Border.Background> |
||||
|
<ImageBrush Source="avares://ControlCatalog/Assets/Sanctuary/main_deep_forest.jpg" |
||||
|
Stretch="UniformToFill" /> |
||||
|
</Border.Background> |
||||
|
<Grid> |
||||
|
<Border ClipToBounds="True" Margin="-1"> |
||||
|
<Border.Background> |
||||
|
<LinearGradientBrush StartPoint="0,1" EndPoint="0,0"> |
||||
|
<GradientStop Offset="0" Color="#66000000" /> |
||||
|
<GradientStop Offset="0.5" Color="Transparent" /> |
||||
|
</LinearGradientBrush> |
||||
|
</Border.Background> |
||||
|
</Border> |
||||
|
<StackPanel VerticalAlignment="Bottom" Margin="16,0,16,16" Spacing="4"> |
||||
|
<Border CornerRadius="12" Background="#33f47b25" Padding="8,4" HorizontalAlignment="Left"> |
||||
|
<TextBlock Text="FOREST" FontSize="10" FontWeight="Bold" Foreground="#f47b25" /> |
||||
|
</Border> |
||||
|
<TextBlock Text="Deep Forest" FontSize="22" FontWeight="Bold" Foreground="White" /> |
||||
|
<TextBlock Text="Quiet trails in Oregon, USA" FontSize="12" Foreground="#CCffffff" /> |
||||
|
</StackPanel> |
||||
|
</Grid> |
||||
|
</Border> |
||||
|
|
||||
|
<!-- Card 2: Arctic Silence --> |
||||
|
<Border Margin="16,0,16,12" CornerRadius="16" ClipToBounds="True" Height="240"> |
||||
|
<Border.Background> |
||||
|
<ImageBrush Source="avares://ControlCatalog/Assets/Sanctuary/main_arctic_silence.jpg" |
||||
|
Stretch="UniformToFill" /> |
||||
|
</Border.Background> |
||||
|
<Grid> |
||||
|
<Border ClipToBounds="True" Margin="-1"> |
||||
|
<Border.Background> |
||||
|
<LinearGradientBrush StartPoint="0,1" EndPoint="0,0"> |
||||
|
<GradientStop Offset="0" Color="#66000000" /> |
||||
|
<GradientStop Offset="0.5" Color="Transparent" /> |
||||
|
</LinearGradientBrush> |
||||
|
</Border.Background> |
||||
|
</Border> |
||||
|
<StackPanel VerticalAlignment="Bottom" Margin="16,0,16,16" Spacing="4"> |
||||
|
<Border CornerRadius="12" Background="#33f47b25" Padding="8,4" HorizontalAlignment="Left"> |
||||
|
<TextBlock Text="ALPINE" FontSize="10" FontWeight="Bold" Foreground="#f47b25" /> |
||||
|
</Border> |
||||
|
<TextBlock Text="Arctic Silence" FontSize="22" FontWeight="Bold" Foreground="White" /> |
||||
|
<TextBlock Text="Remote retreats in Svalbard" FontSize="12" Foreground="#CCffffff" /> |
||||
|
</StackPanel> |
||||
|
</Grid> |
||||
|
</Border> |
||||
|
|
||||
|
<!-- Card 3: Desert Sands --> |
||||
|
<Border Margin="16,0,16,20" CornerRadius="16" ClipToBounds="True" Height="240"> |
||||
|
<Border.Background> |
||||
|
<ImageBrush Source="avares://ControlCatalog/Assets/Sanctuary/main_desert_sands.jpg" |
||||
|
Stretch="UniformToFill" /> |
||||
|
</Border.Background> |
||||
|
<Grid> |
||||
|
<Border ClipToBounds="True" Margin="-1"> |
||||
|
<Border.Background> |
||||
|
<LinearGradientBrush StartPoint="0,1" EndPoint="0,0"> |
||||
|
<GradientStop Offset="0" Color="#66000000" /> |
||||
|
<GradientStop Offset="0.5" Color="Transparent" /> |
||||
|
</LinearGradientBrush> |
||||
|
</Border.Background> |
||||
|
</Border> |
||||
|
<StackPanel VerticalAlignment="Bottom" Margin="16,0,16,16" Spacing="4"> |
||||
|
<Border CornerRadius="12" Background="#33f47b25" Padding="8,4" HorizontalAlignment="Left"> |
||||
|
<TextBlock Text="DESERT" FontSize="10" FontWeight="Bold" Foreground="#f47b25" /> |
||||
|
</Border> |
||||
|
<TextBlock Text="Desert Sands" FontSize="22" FontWeight="Bold" Foreground="White" /> |
||||
|
<TextBlock Text="Star gazing in Wadi Rum" FontSize="12" Foreground="#CCffffff" /> |
||||
|
</StackPanel> |
||||
|
</Grid> |
||||
|
</Border> |
||||
|
|
||||
|
</StackPanel> |
||||
|
</ScrollViewer> |
||||
|
</ContentPage> |
||||
|
|
||||
|
<!-- Explore Tab --> |
||||
|
<ContentPage Header="Explore" |
||||
|
Background="#221710"> |
||||
|
<ContentPage.Icon> |
||||
|
<StreamGeometry>M12 10.9c-.61 0-1.1.49-1.1 1.1s.49 1.1 1.1 1.1c.61 0 1.1-.49 1.1-1.1s-.49-1.1-1.1-1.1zM12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm2.19 12.19L6 18l3.81-8.19L18 6l-3.81 8.19z</StreamGeometry> |
||||
|
</ContentPage.Icon> |
||||
|
<StackPanel VerticalAlignment="Center" HorizontalAlignment="Center" |
||||
|
Spacing="12" Margin="32"> |
||||
|
<TextBlock Text="✦" FontSize="48" Foreground="#33FFFFFF" HorizontalAlignment="Center" /> |
||||
|
<TextBlock Text="Explore" FontSize="20" FontWeight="Bold" Foreground="White" |
||||
|
HorizontalAlignment="Center" /> |
||||
|
<TextBlock Text="Discover new destinations around the world." |
||||
|
FontSize="13" Foreground="#80FFFFFF" |
||||
|
TextAlignment="Center" TextWrapping="Wrap" /> |
||||
|
</StackPanel> |
||||
|
</ContentPage> |
||||
|
|
||||
|
<!-- Saved Tab --> |
||||
|
<ContentPage Header="Saved" |
||||
|
Background="#221710"> |
||||
|
<ContentPage.Icon> |
||||
|
<StreamGeometry>M12 21.35l-1.45-1.32C5.4 15.36 2 12.28 2 8.5 2 5.42 4.42 3 7.5 3c1.74 0 3.41.81 4.5 2.09C13.09 3.81 14.76 3 16.5 3 19.58 3 22 5.42 22 8.5c0 3.78-3.4 6.86-8.55 11.54L12 21.35z</StreamGeometry> |
||||
|
</ContentPage.Icon> |
||||
|
<StackPanel VerticalAlignment="Center" HorizontalAlignment="Center" |
||||
|
Spacing="12" Margin="32"> |
||||
|
<TextBlock Text="♡" FontSize="48" Foreground="#33FFFFFF" HorizontalAlignment="Center" /> |
||||
|
<TextBlock Text="Saved" FontSize="20" FontWeight="Bold" Foreground="White" |
||||
|
HorizontalAlignment="Center" /> |
||||
|
<TextBlock Text="Your saved destinations will appear here." |
||||
|
FontSize="13" Foreground="#80FFFFFF" |
||||
|
TextAlignment="Center" TextWrapping="Wrap" /> |
||||
|
</StackPanel> |
||||
|
</ContentPage> |
||||
|
|
||||
|
<!-- Profile Tab --> |
||||
|
<ContentPage Header="Profile" |
||||
|
Background="#221710"> |
||||
|
<ContentPage.Icon> |
||||
|
<StreamGeometry>M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z</StreamGeometry> |
||||
|
</ContentPage.Icon> |
||||
|
<StackPanel VerticalAlignment="Center" HorizontalAlignment="Center" |
||||
|
Spacing="12" Margin="32"> |
||||
|
<TextBlock Text="◉" FontSize="48" Foreground="#33FFFFFF" HorizontalAlignment="Center" /> |
||||
|
<TextBlock Text="Profile" FontSize="20" FontWeight="Bold" Foreground="White" |
||||
|
HorizontalAlignment="Center" /> |
||||
|
<TextBlock Text="Your profile and settings will appear here." |
||||
|
FontSize="13" Foreground="#80FFFFFF" |
||||
|
TextAlignment="Center" TextWrapping="Wrap" /> |
||||
|
</StackPanel> |
||||
|
</ContentPage> |
||||
|
|
||||
|
</TabbedPage> |
||||
|
|
||||
|
</Grid> |
||||
|
|
||||
|
</DockPanel> |
||||
|
</UserControl> |
||||
@ -0,0 +1,11 @@ |
|||||
|
using Avalonia.Controls; |
||||
|
|
||||
|
namespace ControlCatalog.Pages; |
||||
|
|
||||
|
public partial class SanctuaryMainPage : UserControl |
||||
|
{ |
||||
|
public SanctuaryMainPage() |
||||
|
{ |
||||
|
InitializeComponent(); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,335 @@ |
|||||
|
<UserControl xmlns="https://github.com/avaloniaui" |
||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" |
||||
|
x:Class="ControlCatalog.Pages.SanctuaryShowcasePage"> |
||||
|
<UserControl.Styles> |
||||
|
<!-- Orange primary button --> |
||||
|
<Style Selector="Button.primary /template/ ContentPresenter#PART_ContentPresenter"> |
||||
|
<Setter Property="Background" Value="#f47b25" /> |
||||
|
<Setter Property="CornerRadius" Value="{TemplateBinding CornerRadius}" /> |
||||
|
</Style> |
||||
|
<Style Selector="Button.primary:pointerover /template/ ContentPresenter#PART_ContentPresenter"> |
||||
|
<Setter Property="Background" Value="#e0701f" /> |
||||
|
</Style> |
||||
|
<Style Selector="Button.primary:pressed /template/ ContentPresenter#PART_ContentPresenter"> |
||||
|
<Setter Property="Background" Value="#c9611a" /> |
||||
|
</Style> |
||||
|
|
||||
|
<!-- Glass button (semi-transparent white) --> |
||||
|
<Style Selector="Button.glass /template/ ContentPresenter#PART_ContentPresenter"> |
||||
|
<Setter Property="Background" Value="#18FFFFFF" /> |
||||
|
<Setter Property="CornerRadius" Value="{TemplateBinding CornerRadius}" /> |
||||
|
</Style> |
||||
|
<Style Selector="Button.glass:pointerover /template/ ContentPresenter#PART_ContentPresenter"> |
||||
|
<Setter Property="Background" Value="#2AFFFFFF" /> |
||||
|
</Style> |
||||
|
<Style Selector="Button.glass:pressed /template/ ContentPresenter#PART_ContentPresenter"> |
||||
|
<Setter Property="Background" Value="#10FFFFFF" /> |
||||
|
</Style> |
||||
|
|
||||
|
</UserControl.Styles> |
||||
|
|
||||
|
<DockPanel> |
||||
|
|
||||
|
<ScrollViewer DockPanel.Dock="Right" Width="220"> |
||||
|
<StackPanel Margin="12" Spacing="8"> |
||||
|
<TextBlock Text="Sanctuary" FontSize="16" FontWeight="SemiBold" |
||||
|
Foreground="{DynamicResource SystemControlHighlightAccentBrush}" /> |
||||
|
<TextBlock TextWrapping="Wrap" FontSize="12" Opacity="0.7" |
||||
|
Text="A travel discovery app with 3 full-screen immersive pages. Uses PipsPager with custom pill-shaped indicators. Swipe, use arrow keys, tap the CTA buttons, or click the pip indicators to navigate." /> |
||||
|
<Separator /> |
||||
|
<TextBlock Text="Design" FontSize="13" FontWeight="SemiBold" /> |
||||
|
<TextBlock FontSize="12" Text="Theme: Dark (#221710)" /> |
||||
|
<TextBlock FontSize="12" Text="Primary: #f47b25 (warm orange)" /> |
||||
|
<Separator /> |
||||
|
<TextBlock Text="Pages" FontSize="13" FontWeight="SemiBold" /> |
||||
|
<TextBlock FontSize="12" TextWrapping="Wrap" Text="1. Explore the Unknown — mountain backdrop" /> |
||||
|
<TextBlock FontSize="12" TextWrapping="Wrap" Text="2. Hidden Sanctuaries — forest scene" /> |
||||
|
<TextBlock FontSize="12" TextWrapping="Wrap" Text="3. Urban Adventures — neon city" /> |
||||
|
</StackPanel> |
||||
|
</ScrollViewer> |
||||
|
|
||||
|
<Border DockPanel.Dock="Right" Width="1" |
||||
|
Background="{DynamicResource SystemControlForegroundBaseMediumLowBrush}" /> |
||||
|
|
||||
|
<Border BorderBrush="{DynamicResource SystemControlForegroundBaseMediumLowBrush}" |
||||
|
BorderThickness="1" CornerRadius="8" ClipToBounds="True" Margin="12"> |
||||
|
<Grid> |
||||
|
<CarouselPage x:Name="DemoCarousel" IsGestureEnabled="True"> |
||||
|
|
||||
|
<!-- Page 1: Explore the Unknown --> |
||||
|
<ContentPage HorizontalContentAlignment="Stretch" |
||||
|
VerticalContentAlignment="Stretch"> |
||||
|
<ContentPage.Background> |
||||
|
<ImageBrush Source="avares://ControlCatalog/Assets/Sanctuary/mountain_bg.jpg" |
||||
|
Stretch="UniformToFill" /> |
||||
|
</ContentPage.Background> |
||||
|
<Grid> |
||||
|
<Border> |
||||
|
<Border.Background> |
||||
|
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1"> |
||||
|
<GradientStop Offset="0" Color="Transparent" /> |
||||
|
<GradientStop Offset="0.35" Color="#55221710" /> |
||||
|
<GradientStop Offset="1" Color="#EE221710" /> |
||||
|
</LinearGradientBrush> |
||||
|
</Border.Background> |
||||
|
</Border> |
||||
|
<Grid RowDefinitions="*,Auto"> |
||||
|
<StackPanel Grid.Row="1" Margin="28,0,28,44" Spacing="0" |
||||
|
HorizontalAlignment="Center"> |
||||
|
|
||||
|
<TextBlock Text="Explore the Unknown" |
||||
|
FontSize="36" FontWeight="Bold" Foreground="White" |
||||
|
TextAlignment="Center" TextWrapping="Wrap" |
||||
|
MaxWidth="300" Margin="0,0,0,14" /> |
||||
|
|
||||
|
<TextBlock Text="Embark on an unforgettable adventure through pristine wilderness and discover the hidden wonders of the world's most majestic peaks." |
||||
|
FontSize="14" Foreground="#CAffffff" |
||||
|
TextAlignment="Center" TextWrapping="Wrap" |
||||
|
MaxWidth="300" Margin="0,0,0,24" /> |
||||
|
|
||||
|
<Button Classes="primary" |
||||
|
Foreground="White" FontWeight="Bold" FontSize="16" |
||||
|
CornerRadius="24" Padding="24,16" |
||||
|
HorizontalAlignment="Stretch" |
||||
|
HorizontalContentAlignment="Center" |
||||
|
Click="OnPage1CTA" Margin="0,0,0,48"> |
||||
|
<StackPanel Orientation="Horizontal" Spacing="10" HorizontalAlignment="Center"> |
||||
|
<TextBlock Text="Start Journey" Foreground="White" |
||||
|
FontWeight="Bold" VerticalAlignment="Center" /> |
||||
|
<TextBlock Text="→" Foreground="White" VerticalAlignment="Center" /> |
||||
|
</StackPanel> |
||||
|
</Button> |
||||
|
|
||||
|
</StackPanel> |
||||
|
</Grid> |
||||
|
</Grid> |
||||
|
</ContentPage> |
||||
|
|
||||
|
<!-- Page 2: Hidden Sanctuaries --> |
||||
|
<ContentPage HorizontalContentAlignment="Stretch" |
||||
|
VerticalContentAlignment="Stretch"> |
||||
|
<ContentPage.Background> |
||||
|
<ImageBrush Source="avares://ControlCatalog/Assets/Sanctuary/forest_bg.jpg" |
||||
|
Stretch="UniformToFill" /> |
||||
|
</ContentPage.Background> |
||||
|
<Grid> |
||||
|
<Border> |
||||
|
<Border.Background> |
||||
|
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1"> |
||||
|
<GradientStop Offset="0" Color="#88221710" /> |
||||
|
<GradientStop Offset="0.3" Color="Transparent" /> |
||||
|
<GradientStop Offset="0.75" Color="#55221710" /> |
||||
|
<GradientStop Offset="1" Color="#CC221710" /> |
||||
|
</LinearGradientBrush> |
||||
|
</Border.Background> |
||||
|
</Border> |
||||
|
|
||||
|
<Grid RowDefinitions="Auto,*,Auto"> |
||||
|
|
||||
|
<!-- Logo bar --> |
||||
|
<StackPanel Grid.Row="0" Orientation="Horizontal" Spacing="8" |
||||
|
Margin="20,22,20,0"> |
||||
|
<Panel Width="28" Height="28"> |
||||
|
<Ellipse Fill="#f47b25" /> |
||||
|
<TextBlock Text="▲" Foreground="White" FontSize="12" FontWeight="Bold" |
||||
|
HorizontalAlignment="Center" VerticalAlignment="Center" /> |
||||
|
</Panel> |
||||
|
<TextBlock Text="SANCTUARY" Foreground="White" FontWeight="Bold" |
||||
|
FontSize="15" VerticalAlignment="Center" /> |
||||
|
</StackPanel> |
||||
|
|
||||
|
<!-- Center content --> |
||||
|
<StackPanel Grid.Row="1" Margin="24,0,24,0" Spacing="18" |
||||
|
HorizontalAlignment="Center" VerticalAlignment="Center"> |
||||
|
|
||||
|
<Border CornerRadius="20" BorderBrush="#50f47b25" BorderThickness="1" |
||||
|
Background="#1Af47b25" HorizontalAlignment="Center" Padding="14,6"> |
||||
|
<StackPanel Orientation="Horizontal" Spacing="6"> |
||||
|
<TextBlock Text="◎" Foreground="#f47b25" FontSize="11" VerticalAlignment="Center" /> |
||||
|
<TextBlock Text="VOLUME II: SECLUSION" Foreground="#f47b25" |
||||
|
FontSize="11" FontWeight="Bold" /> |
||||
|
</StackPanel> |
||||
|
</Border> |
||||
|
|
||||
|
<StackPanel Spacing="0" HorizontalAlignment="Center"> |
||||
|
<TextBlock Text="Hidden" Foreground="White" |
||||
|
FontSize="54" FontWeight="Bold" TextAlignment="Center" /> |
||||
|
<TextBlock Text="Sanctuaries" Foreground="White" |
||||
|
FontSize="54" FontStyle="Italic" FontWeight="Light" |
||||
|
TextAlignment="Center" /> |
||||
|
</StackPanel> |
||||
|
|
||||
|
<TextBlock Text="Find your peace in the world's most secluded natural wonders. From misty forest groves to still mountain lakes, discover the quiet beauty of nature's best-kept secrets." |
||||
|
Foreground="#CCffffff" FontSize="14" |
||||
|
TextAlignment="Center" TextWrapping="Wrap" MaxWidth="310" /> |
||||
|
|
||||
|
<StackPanel Spacing="10" HorizontalAlignment="Center"> |
||||
|
<Button Classes="primary" |
||||
|
Foreground="#221710" FontWeight="Bold" FontSize="15" |
||||
|
CornerRadius="24" Padding="32,16" |
||||
|
HorizontalContentAlignment="Center" MinWidth="220" |
||||
|
Click="OnPage2CTA"> |
||||
|
<StackPanel Orientation="Horizontal" Spacing="8"> |
||||
|
<TextBlock Text="Discover More" Foreground="#221710" |
||||
|
FontWeight="Bold" VerticalAlignment="Center" /> |
||||
|
<TextBlock Text="→" Foreground="#221710" VerticalAlignment="Center" /> |
||||
|
</StackPanel> |
||||
|
</Button> |
||||
|
<Button Classes="glass" |
||||
|
Foreground="White" FontWeight="Bold" FontSize="15" |
||||
|
CornerRadius="24" Padding="32,16" |
||||
|
HorizontalContentAlignment="Center" MinWidth="220" |
||||
|
Click="OnPage2CTA"> |
||||
|
<StackPanel Orientation="Horizontal" Spacing="8"> |
||||
|
<TextBlock Text="▷" Foreground="White" VerticalAlignment="Center" /> |
||||
|
<TextBlock Text="Experience" Foreground="White" |
||||
|
FontWeight="Bold" VerticalAlignment="Center" /> |
||||
|
</StackPanel> |
||||
|
</Button> |
||||
|
</StackPanel> |
||||
|
|
||||
|
</StackPanel> |
||||
|
|
||||
|
<!-- Footer: location + social --> |
||||
|
<StackPanel Grid.Row="2" Spacing="14" Margin="0,0,0,44"> |
||||
|
|
||||
|
<Grid ColumnDefinitions="*,Auto" Margin="20,0,20,0"> |
||||
|
<StackPanel Grid.Column="0" Orientation="Horizontal" Spacing="5" |
||||
|
VerticalAlignment="Center"> |
||||
|
<TextBlock Text="⊙" Foreground="#80FFFFFF" FontSize="11" |
||||
|
VerticalAlignment="Center" /> |
||||
|
<TextBlock Text="NORDIC HIGHLANDS" Foreground="#80FFFFFF" |
||||
|
FontSize="10" FontWeight="SemiBold" /> |
||||
|
</StackPanel> |
||||
|
<StackPanel Grid.Column="1" Orientation="Horizontal" Spacing="14"> |
||||
|
<TextBlock Text="Instagram" Foreground="#80FFFFFF" |
||||
|
FontSize="10" FontWeight="SemiBold" /> |
||||
|
<TextBlock Text="Pinterest" Foreground="#80FFFFFF" |
||||
|
FontSize="10" FontWeight="SemiBold" /> |
||||
|
</StackPanel> |
||||
|
</Grid> |
||||
|
|
||||
|
</StackPanel> |
||||
|
</Grid> |
||||
|
</Grid> |
||||
|
</ContentPage> |
||||
|
|
||||
|
<!-- Page 3: Urban Adventures --> |
||||
|
<ContentPage HorizontalContentAlignment="Stretch" |
||||
|
VerticalContentAlignment="Stretch"> |
||||
|
<ContentPage.Background> |
||||
|
<ImageBrush Source="avares://ControlCatalog/Assets/Sanctuary/city_bg.jpg" |
||||
|
Stretch="UniformToFill" /> |
||||
|
</ContentPage.Background> |
||||
|
<Grid> |
||||
|
<Border> |
||||
|
<Border.Background> |
||||
|
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1"> |
||||
|
<GradientStop Offset="0" Color="Transparent" /> |
||||
|
<GradientStop Offset="0.35" Color="#55221710" /> |
||||
|
<GradientStop Offset="0.6" Color="#99221710" /> |
||||
|
<GradientStop Offset="1" Color="#EE221710" /> |
||||
|
</LinearGradientBrush> |
||||
|
</Border.Background> |
||||
|
</Border> |
||||
|
|
||||
|
<Grid RowDefinitions="*,Auto"> |
||||
|
<StackPanel Grid.Row="1" Margin="28,0,28,44" Spacing="0" |
||||
|
HorizontalAlignment="Center"> |
||||
|
|
||||
|
<TextBlock Text="Urban Adventures" |
||||
|
FontSize="44" FontWeight="Bold" Foreground="White" |
||||
|
TextAlignment="Center" TextWrapping="Wrap" |
||||
|
MaxWidth="320" Margin="0,0,0,14" /> |
||||
|
|
||||
|
<Border Height="5" Width="88" CornerRadius="3" |
||||
|
Background="#f47b25" HorizontalAlignment="Center" |
||||
|
Margin="0,0,0,18" /> |
||||
|
|
||||
|
<TextBlock Text="Experience the electric pulse of the city that never sleeps. Explore hidden gems and neon-lit wonders around every corner." |
||||
|
FontSize="14" Foreground="#CAffffff" |
||||
|
TextAlignment="Center" TextWrapping="Wrap" |
||||
|
MaxWidth="300" Margin="0,0,0,24" /> |
||||
|
|
||||
|
<Button Classes="primary" |
||||
|
Foreground="White" FontWeight="Bold" FontSize="16" |
||||
|
CornerRadius="24" Padding="24,16" |
||||
|
HorizontalAlignment="Stretch" |
||||
|
HorizontalContentAlignment="Center" |
||||
|
Click="OnPage3CTA" Margin="0,0,0,48"> |
||||
|
<TextBlock Text="Get Started" Foreground="White" FontWeight="Bold" /> |
||||
|
</Button> |
||||
|
|
||||
|
</StackPanel> |
||||
|
</Grid> |
||||
|
</Grid> |
||||
|
</ContentPage> |
||||
|
|
||||
|
</CarouselPage> |
||||
|
|
||||
|
<PipsPager HorizontalAlignment="Center" |
||||
|
VerticalAlignment="Bottom" Margin="0,0,0,20" |
||||
|
NumberOfPages="3" |
||||
|
SelectedPageIndex="{Binding #DemoCarousel.SelectedIndex}" |
||||
|
IsPreviousButtonVisible="False" |
||||
|
IsNextButtonVisible="False"> |
||||
|
<PipsPager.Styles> |
||||
|
<Style Selector="PipsPager /template/ ListBox ListBoxItem"> |
||||
|
<Setter Property="Width" Value="38" /> |
||||
|
<Setter Property="Height" Value="24" /> |
||||
|
<Setter Property="Padding" Value="0" /> |
||||
|
<Setter Property="Margin" Value="2,0" /> |
||||
|
<Setter Property="MinWidth" Value="0" /> |
||||
|
<Setter Property="MinHeight" Value="0" /> |
||||
|
<Setter Property="ClipToBounds" Value="False" /> |
||||
|
<Setter Property="VerticalAlignment" Value="Center" /> |
||||
|
<Setter Property="Template"> |
||||
|
<ControlTemplate> |
||||
|
<Grid Background="Transparent"> |
||||
|
<Border Name="Pip" |
||||
|
Width="8" Height="8" CornerRadius="4" |
||||
|
HorizontalAlignment="Center" VerticalAlignment="Center" |
||||
|
Background="#4DFFFFFF"> |
||||
|
<Border.Transitions> |
||||
|
<Transitions> |
||||
|
<DoubleTransition Property="Width" Duration="0:0:0.25" Easing="CubicEaseOut" /> |
||||
|
<DoubleTransition Property="Height" Duration="0:0:0.25" Easing="CubicEaseOut" /> |
||||
|
<CornerRadiusTransition Property="CornerRadius" Duration="0:0:0.25" Easing="CubicEaseOut" /> |
||||
|
<BrushTransition Property="Background" Duration="0:0:0.25" /> |
||||
|
</Transitions> |
||||
|
</Border.Transitions> |
||||
|
</Border> |
||||
|
</Grid> |
||||
|
</ControlTemplate> |
||||
|
</Setter> |
||||
|
</Style> |
||||
|
<Style Selector="PipsPager /template/ ListBox ListBoxItem:pointerover /template/ Border#Pip"> |
||||
|
<Setter Property="Width" Value="10" /> |
||||
|
<Setter Property="Height" Value="10" /> |
||||
|
<Setter Property="CornerRadius" Value="5" /> |
||||
|
<Setter Property="Background" Value="#80FFFFFF" /> |
||||
|
</Style> |
||||
|
<Style Selector="PipsPager /template/ ListBox ListBoxItem:selected /template/ Border#Pip"> |
||||
|
<Setter Property="Width" Value="32" /> |
||||
|
<Setter Property="Height" Value="8" /> |
||||
|
<Setter Property="CornerRadius" Value="4" /> |
||||
|
<Setter Property="Background" Value="#f47b25" /> |
||||
|
</Style> |
||||
|
<Style Selector="PipsPager /template/ ListBox ListBoxItem:selected:pointerover /template/ Border#Pip"> |
||||
|
<Setter Property="Width" Value="32" /> |
||||
|
<Setter Property="Height" Value="8" /> |
||||
|
<Setter Property="CornerRadius" Value="4" /> |
||||
|
<Setter Property="Background" Value="#e0701f" /> |
||||
|
</Style> |
||||
|
<Style Selector="PipsPager /template/ ListBox ListBoxItem:pressed /template/ Border#Pip"> |
||||
|
<Setter Property="Width" Value="8" /> |
||||
|
<Setter Property="Height" Value="8" /> |
||||
|
<Setter Property="Background" Value="#f47b25" /> |
||||
|
</Style> |
||||
|
</PipsPager.Styles> |
||||
|
</PipsPager> |
||||
|
|
||||
|
</Grid> |
||||
|
</Border> |
||||
|
</DockPanel> |
||||
|
</UserControl> |
||||
@ -0,0 +1,70 @@ |
|||||
|
using System.Linq; |
||||
|
using Avalonia; |
||||
|
using Avalonia.Controls; |
||||
|
using Avalonia.Interactivity; |
||||
|
using Avalonia.Layout; |
||||
|
using Avalonia.Media; |
||||
|
using Avalonia.VisualTree; |
||||
|
|
||||
|
namespace ControlCatalog.Pages; |
||||
|
|
||||
|
public partial class SanctuaryShowcasePage : UserControl |
||||
|
{ |
||||
|
public SanctuaryShowcasePage() |
||||
|
{ |
||||
|
InitializeComponent(); |
||||
|
} |
||||
|
|
||||
|
private void OnPage1CTA(object? sender, RoutedEventArgs e) |
||||
|
{ |
||||
|
DemoCarousel.SelectedIndex = 1; |
||||
|
} |
||||
|
|
||||
|
private void OnPage2CTA(object? sender, RoutedEventArgs e) |
||||
|
{ |
||||
|
DemoCarousel.SelectedIndex = 2; |
||||
|
} |
||||
|
|
||||
|
private async void OnPage3CTA(object? sender, RoutedEventArgs e) |
||||
|
{ |
||||
|
var nav = this.FindAncestorOfType<NavigationPage>(); |
||||
|
if (nav == null) |
||||
|
return; |
||||
|
|
||||
|
var carouselWrapper = nav.NavigationStack.LastOrDefault(); |
||||
|
|
||||
|
var headerGrid = new Grid { ColumnDefinitions = new ColumnDefinitions("*, Auto") }; |
||||
|
headerGrid.Children.Add(new TextBlock |
||||
|
{ |
||||
|
Text = "Sanctuary", |
||||
|
VerticalAlignment = VerticalAlignment.Center |
||||
|
}); |
||||
|
var closeIcon = Geometry.Parse( |
||||
|
"M4.397 4.397a1 1 0 0 1 1.414 0L12 10.585l6.19-6.188a1 1 0 0 1 1.414 1.414L13.413 12l6.19 6.189a1 1 0 0 1-1.414 1.414L12 13.413l-6.189 6.19a1 1 0 0 1-1.414-1.414L10.585 12 4.397 5.811a1 1 0 0 1 0-1.414z"); |
||||
|
var closeBtn = new Button |
||||
|
{ |
||||
|
Content = new PathIcon { Data = closeIcon }, |
||||
|
Background = Brushes.Transparent, |
||||
|
BorderThickness = new Thickness(0), |
||||
|
Padding = new Thickness(8, 4), |
||||
|
VerticalAlignment = VerticalAlignment.Center |
||||
|
}; |
||||
|
Grid.SetColumn(closeBtn, 1); |
||||
|
headerGrid.Children.Add(closeBtn); |
||||
|
closeBtn.Click += async (_, _) => await nav.PopAsync(null); |
||||
|
|
||||
|
var mainPage = new ContentPage |
||||
|
{ |
||||
|
Header = headerGrid, |
||||
|
Content = new SanctuaryMainPage() |
||||
|
}; |
||||
|
NavigationPage.SetHasBackButton(mainPage, false); |
||||
|
|
||||
|
await nav.PushAsync(mainPage); |
||||
|
|
||||
|
if (carouselWrapper != null) |
||||
|
{ |
||||
|
nav.RemovePage(carouselWrapper); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,95 @@ |
|||||
|
<UserControl xmlns="https://github.com/avaloniaui" |
||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" |
||||
|
x:Class="ControlCatalog.Pages.CommandBarEventsPage"> |
||||
|
<UserControl.Resources> |
||||
|
<StreamGeometry x:Key="AddIcon">M19,13H13V19H11V13H5V11H11V5H13V11H19V13Z</StreamGeometry> |
||||
|
<StreamGeometry x:Key="SaveIcon">M15,9H5V5H15M12,19A3,3 0 0,1 9,16A3,3 0 0,1 12,13A3,3 0 0,1 15,16A3,3 0 0,1 12,19M17,3H5C3.89,3 3,3.9 3,5V19A2,2 0 0,0 5,21H19A2,2 0 0,0 21,19V7L17,3Z</StreamGeometry> |
||||
|
<StreamGeometry x:Key="ShareIcon">M18,16.08C17.24,16.08 16.56,16.38 16.04,16.85L8.91,12.7C8.96,12.47 9,12.24 9,12C9,11.76 8.96,11.53 8.91,11.3L15.96,7.19C16.5,7.69 17.21,8 18,8A3,3 0 0,0 21,5A3,3 0 0,0 18,2A3,3 0 0,0 15,5C15,5.24 15.04,5.47 15.09,5.7L8.04,9.81C7.5,9.31 6.79,9 6,9A3,3 0 0,0 3,12A3,3 0 0,0 6,15C6.79,15 7.5,14.69 8.04,14.19L15.16,18.34C15.11,18.55 15.08,18.77 15.08,19C15.08,20.61 16.39,21.91 18,21.91C19.61,21.91 20.92,20.61 20.92,19C20.92,17.39 19.61,16.08 18,16.08Z</StreamGeometry> |
||||
|
<StreamGeometry x:Key="ExportIcon">M14,2H6A2,2 0 0,0 4,4V20A2,2 0 0,0 6,22H18A2,2 0 0,0 20,20V8L14,2M18,20H6V4H13V9H18V20M16,11V18.1L13.9,16L11.1,18.8L8.3,16L11.1,13.2L9,11.1L16,11Z</StreamGeometry> |
||||
|
<StreamGeometry x:Key="DeleteIcon">M19,4H15.5L14.5,3H9.5L8.5,4H5V6H19M6,19A2,2 0 0,0 8,21H16A2,2 0 0,0 18,19V7H6V19Z</StreamGeometry> |
||||
|
</UserControl.Resources> |
||||
|
|
||||
|
<DockPanel> |
||||
|
<ScrollViewer DockPanel.Dock="Right" Width="280"> |
||||
|
<StackPanel Margin="12" Spacing="8"> |
||||
|
<TextBlock Text="Actions" FontWeight="SemiBold" FontSize="16" |
||||
|
Foreground="{DynamicResource SystemControlHighlightAccentBrush}" /> |
||||
|
|
||||
|
<CheckBox x:Name="IsOpenCheck" |
||||
|
Content="IsOpen" |
||||
|
IsCheckedChanged="OnIsOpenChanged" /> |
||||
|
|
||||
|
<Button Content="+ Add Primary" |
||||
|
HorizontalAlignment="Stretch" |
||||
|
Click="OnAddPrimary" /> |
||||
|
|
||||
|
<Button Content="- Remove Primary" |
||||
|
HorizontalAlignment="Stretch" |
||||
|
Click="OnRemovePrimary" /> |
||||
|
|
||||
|
<Button Content="+ Add Secondary" |
||||
|
HorizontalAlignment="Stretch" |
||||
|
Click="OnAddSecondary" /> |
||||
|
|
||||
|
<Button Content="- Remove Secondary" |
||||
|
HorizontalAlignment="Stretch" |
||||
|
Click="OnRemoveSecondary" /> |
||||
|
|
||||
|
<Button Content="Clear Log" |
||||
|
HorizontalAlignment="Stretch" |
||||
|
Click="OnClearLog" /> |
||||
|
|
||||
|
<Separator /> |
||||
|
|
||||
|
<TextBlock Text="State" FontWeight="SemiBold" /> |
||||
|
<TextBlock x:Name="StateText" |
||||
|
FontSize="12" |
||||
|
Opacity="0.7" |
||||
|
TextWrapping="Wrap" /> |
||||
|
|
||||
|
<Separator /> |
||||
|
|
||||
|
<TextBlock Text="About" FontWeight="SemiBold" /> |
||||
|
<TextBlock FontSize="12" Opacity="0.7" TextWrapping="Wrap" |
||||
|
Text="Opening/Opened fire when the overflow opens. Closing/Closed fire when it closes. The log also records item clicks and command execution while the state panel reflects IsOpen, HasSecondaryCommands, and IsOverflowButtonVisible in real time." /> |
||||
|
</StackPanel> |
||||
|
</ScrollViewer> |
||||
|
|
||||
|
<Border DockPanel.Dock="Right" Width="1" Background="{DynamicResource SystemControlForegroundBaseMediumLowBrush}" /> |
||||
|
|
||||
|
<ScrollViewer> |
||||
|
<StackPanel Spacing="12" Margin="12,12,12,0"> |
||||
|
<TextBlock Classes="h2">Observe CommandBar overflow events, item invocation, and state changes while opening, closing, and editing the primary and secondary command sets.</TextBlock> |
||||
|
|
||||
|
<CommandBar x:Name="DemoBar" |
||||
|
OverflowButtonVisibility="Auto"> |
||||
|
<CommandBar.PrimaryCommands> |
||||
|
<AppBarButton Label="New"><AppBarButton.Icon><PathIcon Data="{StaticResource AddIcon}" /></AppBarButton.Icon></AppBarButton> |
||||
|
<AppBarButton Label="Save"><AppBarButton.Icon><PathIcon Data="{StaticResource SaveIcon}" /></AppBarButton.Icon></AppBarButton> |
||||
|
<AppBarButton Label="Share"><AppBarButton.Icon><PathIcon Data="{StaticResource ShareIcon}" /></AppBarButton.Icon></AppBarButton> |
||||
|
</CommandBar.PrimaryCommands> |
||||
|
<CommandBar.SecondaryCommands> |
||||
|
<AppBarButton Label="Export"><AppBarButton.Icon><PathIcon Data="{StaticResource ExportIcon}" /></AppBarButton.Icon></AppBarButton> |
||||
|
<AppBarButton Label="Delete"><AppBarButton.Icon><PathIcon Data="{StaticResource DeleteIcon}" /></AppBarButton.Icon></AppBarButton> |
||||
|
</CommandBar.SecondaryCommands> |
||||
|
</CommandBar> |
||||
|
|
||||
|
<Border BorderBrush="{DynamicResource SystemControlForegroundBaseMediumLowBrush}" |
||||
|
BorderThickness="1" |
||||
|
CornerRadius="6" |
||||
|
Padding="10"> |
||||
|
<StackPanel Spacing="6"> |
||||
|
<TextBlock Text="Event Log" FontWeight="SemiBold" /> |
||||
|
<TextBlock x:Name="EventLogText" |
||||
|
FontFamily="Consolas, Menlo, monospace" |
||||
|
FontSize="12" |
||||
|
TextWrapping="Wrap" |
||||
|
MinHeight="140" |
||||
|
Opacity="0.8" |
||||
|
Text="Ready" /> |
||||
|
</StackPanel> |
||||
|
</Border> |
||||
|
</StackPanel> |
||||
|
</ScrollViewer> |
||||
|
</DockPanel> |
||||
|
</UserControl> |
||||
@ -0,0 +1,220 @@ |
|||||
|
using System.Collections.Generic; |
||||
|
using System.Linq; |
||||
|
using Avalonia; |
||||
|
using Avalonia.Controls; |
||||
|
using Avalonia.Interactivity; |
||||
|
using Avalonia.Media; |
||||
|
using MiniMvvm; |
||||
|
|
||||
|
namespace ControlCatalog.Pages |
||||
|
{ |
||||
|
public partial class CommandBarEventsPage : UserControl |
||||
|
{ |
||||
|
private readonly List<string> _log = new(); |
||||
|
private int _primaryCount = 3; |
||||
|
private int _secondaryCount = 2; |
||||
|
|
||||
|
public CommandBarEventsPage() |
||||
|
{ |
||||
|
InitializeComponent(); |
||||
|
Loaded += OnLoaded; |
||||
|
Unloaded += OnUnloaded; |
||||
|
} |
||||
|
|
||||
|
private void OnLoaded(object? sender, RoutedEventArgs e) |
||||
|
{ |
||||
|
DemoBar.Opening += OnOpening; |
||||
|
DemoBar.Opened += OnOpened; |
||||
|
DemoBar.Closing += OnClosing; |
||||
|
DemoBar.Closed += OnClosed; |
||||
|
DemoBar.PropertyChanged += OnBarPropertyChanged; |
||||
|
|
||||
|
AttachItemHandlers(DemoBar.PrimaryCommands); |
||||
|
AttachItemHandlers(DemoBar.SecondaryCommands); |
||||
|
|
||||
|
AppendLog("Ready"); |
||||
|
RefreshState(); |
||||
|
} |
||||
|
|
||||
|
private void OnUnloaded(object? sender, RoutedEventArgs e) |
||||
|
{ |
||||
|
DemoBar.Opening -= OnOpening; |
||||
|
DemoBar.Opened -= OnOpened; |
||||
|
DemoBar.Closing -= OnClosing; |
||||
|
DemoBar.Closed -= OnClosed; |
||||
|
DemoBar.PropertyChanged -= OnBarPropertyChanged; |
||||
|
|
||||
|
DetachItemHandlers(DemoBar.PrimaryCommands); |
||||
|
DetachItemHandlers(DemoBar.SecondaryCommands); |
||||
|
} |
||||
|
|
||||
|
private void OnIsOpenChanged(object? sender, RoutedEventArgs e) |
||||
|
{ |
||||
|
DemoBar.IsOpen = IsOpenCheck.IsChecked == true; |
||||
|
RefreshState(); |
||||
|
} |
||||
|
|
||||
|
private void OnAddPrimary(object? sender, RoutedEventArgs e) |
||||
|
{ |
||||
|
_primaryCount++; |
||||
|
|
||||
|
var button = CreateButton($"Primary {_primaryCount}"); |
||||
|
DemoBar.PrimaryCommands.Add(button); |
||||
|
|
||||
|
AppendLog($"Primary +, {DemoBar.PrimaryCommands.Count}"); |
||||
|
RefreshState(); |
||||
|
} |
||||
|
|
||||
|
private void OnRemovePrimary(object? sender, RoutedEventArgs e) |
||||
|
{ |
||||
|
RemoveLastCommand(DemoBar.PrimaryCommands, "Primary"); |
||||
|
} |
||||
|
|
||||
|
private void OnAddSecondary(object? sender, RoutedEventArgs e) |
||||
|
{ |
||||
|
_secondaryCount++; |
||||
|
|
||||
|
var button = CreateButton($"Secondary {_secondaryCount}"); |
||||
|
DemoBar.SecondaryCommands.Add(button); |
||||
|
|
||||
|
AppendLog($"Secondary +, {DemoBar.SecondaryCommands.Count}"); |
||||
|
RefreshState(); |
||||
|
} |
||||
|
|
||||
|
private void OnRemoveSecondary(object? sender, RoutedEventArgs e) |
||||
|
{ |
||||
|
RemoveLastCommand(DemoBar.SecondaryCommands, "Secondary"); |
||||
|
} |
||||
|
|
||||
|
private void OnClearLog(object? sender, RoutedEventArgs e) |
||||
|
{ |
||||
|
_log.Clear(); |
||||
|
EventLogText.Text = "Log cleared"; |
||||
|
} |
||||
|
|
||||
|
private void OnOpening(object? sender, RoutedEventArgs e) |
||||
|
{ |
||||
|
AppendLog("Opening"); |
||||
|
RefreshState(); |
||||
|
} |
||||
|
|
||||
|
private void OnOpened(object? sender, RoutedEventArgs e) |
||||
|
{ |
||||
|
AppendLog("Opened"); |
||||
|
RefreshState(); |
||||
|
} |
||||
|
|
||||
|
private void OnClosing(object? sender, RoutedEventArgs e) |
||||
|
{ |
||||
|
AppendLog("Closing"); |
||||
|
RefreshState(); |
||||
|
} |
||||
|
|
||||
|
private void OnClosed(object? sender, RoutedEventArgs e) |
||||
|
{ |
||||
|
AppendLog("Closed"); |
||||
|
RefreshState(); |
||||
|
} |
||||
|
|
||||
|
private void OnBarPropertyChanged(object? sender, AvaloniaPropertyChangedEventArgs e) |
||||
|
{ |
||||
|
if (e.Property == CommandBar.IsOpenProperty |
||||
|
|| e.Property == CommandBar.HasSecondaryCommandsProperty |
||||
|
|| e.Property == CommandBar.IsOverflowButtonVisibleProperty) |
||||
|
{ |
||||
|
RefreshState(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private void RefreshState() |
||||
|
{ |
||||
|
StateText.Text = |
||||
|
$"IsOpen: {DemoBar.IsOpen}\n" + |
||||
|
$"HasSecondaryCommands: {DemoBar.HasSecondaryCommands}\n" + |
||||
|
$"IsOverflowButtonVisible: {DemoBar.IsOverflowButtonVisible}\n" + |
||||
|
$"Primary: {DemoBar.PrimaryCommands.Count}\n" + |
||||
|
$"Secondary: {DemoBar.SecondaryCommands.Count}\n" + |
||||
|
$"OverflowItems: {DemoBar.OverflowItems.Count}"; |
||||
|
|
||||
|
IsOpenCheck.IsChecked = DemoBar.IsOpen; |
||||
|
} |
||||
|
|
||||
|
private void OnCommandItemClick(object? sender, RoutedEventArgs e) |
||||
|
{ |
||||
|
if (sender is AppBarButton button) |
||||
|
AppendLog($"Click, {button.Label}, {DescribePlacement(button)}"); |
||||
|
} |
||||
|
|
||||
|
private AppBarButton CreateButton(string label) |
||||
|
{ |
||||
|
var button = new AppBarButton |
||||
|
{ |
||||
|
Label = label, |
||||
|
Icon = new PathIcon |
||||
|
{ |
||||
|
Data = StreamGeometry.Parse("M19,13H13V19H11V13H5V11H11V5H13V11H19V13Z") |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
AttachItemHandler(button); |
||||
|
return button; |
||||
|
} |
||||
|
|
||||
|
private void AttachItemHandlers(IEnumerable<ICommandBarElement> items) |
||||
|
{ |
||||
|
foreach (var item in items) |
||||
|
AttachItemHandler(item); |
||||
|
} |
||||
|
|
||||
|
private void DetachItemHandlers(IEnumerable<ICommandBarElement> items) |
||||
|
{ |
||||
|
foreach (var item in items) |
||||
|
{ |
||||
|
if (item is AppBarButton button) |
||||
|
button.Click -= OnCommandItemClick; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private void AttachItemHandler(ICommandBarElement item) |
||||
|
{ |
||||
|
if (item is not AppBarButton button) |
||||
|
return; |
||||
|
|
||||
|
button.Click -= OnCommandItemClick; |
||||
|
button.Click += OnCommandItemClick; |
||||
|
button.Command = MiniCommand.Create(() => AppendLog($"Command, {button.Label}, {DescribePlacement(button)}")); |
||||
|
} |
||||
|
|
||||
|
private void RemoveLastCommand(IList<ICommandBarElement> items, string bucketName) |
||||
|
{ |
||||
|
if (items.Count == 0) |
||||
|
return; |
||||
|
|
||||
|
var item = items[^1]; |
||||
|
var label = item is AppBarButton button ? button.Label ?? "(unnamed)" : item.GetType().Name; |
||||
|
|
||||
|
if (item is AppBarButton appBarButton) |
||||
|
appBarButton.Click -= OnCommandItemClick; |
||||
|
|
||||
|
items.RemoveAt(items.Count - 1); |
||||
|
|
||||
|
AppendLog($"{bucketName} -, {label}, {items.Count}"); |
||||
|
RefreshState(); |
||||
|
} |
||||
|
|
||||
|
private static string DescribePlacement(AppBarButton button) |
||||
|
{ |
||||
|
return button.IsInOverflow ? "overflow" : "primary"; |
||||
|
} |
||||
|
|
||||
|
private void AppendLog(string message) |
||||
|
{ |
||||
|
_log.Add(message); |
||||
|
|
||||
|
if (_log.Count > 12) |
||||
|
_log.RemoveAt(0); |
||||
|
|
||||
|
EventLogText.Text = string.Join("\n", _log.Select((entry, index) => $"{index + 1,2}. {entry}")); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,113 @@ |
|||||
|
<UserControl xmlns="https://github.com/avaloniaui" |
||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" |
||||
|
x:Class="ControlCatalog.Pages.DrawerPageBreakpointPage"> |
||||
|
<DockPanel> |
||||
|
<ScrollViewer DockPanel.Dock="Right" Width="240"> |
||||
|
<StackPanel Margin="12" Spacing="8"> |
||||
|
<TextBlock Text="Configuration" FontWeight="SemiBold" FontSize="16" |
||||
|
Foreground="{DynamicResource SystemControlHighlightAccentBrush}" /> |
||||
|
|
||||
|
<TextBlock Text="DrawerBreakpointLength" FontSize="13" FontWeight="SemiBold" /> |
||||
|
<TextBlock TextWrapping="Wrap" FontSize="12" Opacity="0.7" |
||||
|
Text="When set, the drawer automatically switches layout based on the available size (width for Left/Right, height for Top/Bottom)." /> |
||||
|
|
||||
|
<Border Background="{DynamicResource SystemControlBackgroundBaseLowBrush}" |
||||
|
CornerRadius="4" Padding="8"> |
||||
|
<StackPanel Spacing="4"> |
||||
|
<Grid ColumnDefinitions="18,*"> |
||||
|
<PathIcon Grid.Column="0" Width="12" Height="12" Opacity="0.7" VerticalAlignment="Top" Margin="0,1,0,0" |
||||
|
Data="M19,11H7.83L12.42,6.41L11,5L4,12L11,19L12.41,17.59L7.83,13H19V11Z" /> |
||||
|
<TextBlock Grid.Column="1" FontSize="11" TextWrapping="Wrap" |
||||
|
Text="Below breakpoint → Overlay (hamburger button, drawer closes)" /> |
||||
|
</Grid> |
||||
|
<Grid ColumnDefinitions="18,*"> |
||||
|
<PathIcon Grid.Column="0" Width="12" Height="12" Opacity="0.7" VerticalAlignment="Top" Margin="0,1,0,0" |
||||
|
Data="M5,13H16.17L11.58,17.59L13,19L20,12L13,5L11.59,6.41L16.17,11H5V13Z" /> |
||||
|
<TextBlock Grid.Column="1" FontSize="11" TextWrapping="Wrap" |
||||
|
Text="Above breakpoint → configured layout, drawer opens automatically" /> |
||||
|
</Grid> |
||||
|
</StackPanel> |
||||
|
</Border> |
||||
|
|
||||
|
<TextBlock Text="Breakpoint value" FontSize="12" Opacity="0.7" /> |
||||
|
<StackPanel Orientation="Horizontal" Spacing="8"> |
||||
|
<Slider x:Name="BreakpointSlider" Minimum="100" Maximum="900" Value="500" |
||||
|
Width="150" ValueChanged="OnBreakpointChanged" /> |
||||
|
<TextBlock x:Name="BreakpointText" Text="500" VerticalAlignment="Center" /> |
||||
|
</StackPanel> |
||||
|
|
||||
|
<Separator /> |
||||
|
|
||||
|
<TextBlock Text="Layout above breakpoint" FontSize="13" FontWeight="SemiBold" /> |
||||
|
<TextBlock TextWrapping="Wrap" FontSize="12" Opacity="0.7" |
||||
|
Text="The DrawerLayoutBehavior used when width exceeds the breakpoint." /> |
||||
|
<ComboBox x:Name="LayoutCombo" SelectedIndex="0" |
||||
|
SelectionChanged="OnLayoutChanged" HorizontalAlignment="Stretch"> |
||||
|
<ComboBoxItem Content="Split" /> |
||||
|
<ComboBoxItem Content="CompactInline" /> |
||||
|
<ComboBoxItem Content="CompactOverlay" /> |
||||
|
</ComboBox> |
||||
|
|
||||
|
<Separator /> |
||||
|
|
||||
|
<TextBlock Text="Status" FontWeight="SemiBold" FontSize="13" /> |
||||
|
<TextBlock x:Name="WidthText" Text="Width: —" Opacity="0.7" /> |
||||
|
<TextBlock x:Name="ModeText" Text="Mode: Overlay" Opacity="0.7" TextWrapping="Wrap" /> |
||||
|
<TextBlock TextWrapping="Wrap" FontSize="11" Opacity="0.6" |
||||
|
Text="Resize the window to see the layout switch automatically." /> |
||||
|
</StackPanel> |
||||
|
</ScrollViewer> |
||||
|
|
||||
|
<Border DockPanel.Dock="Right" Width="1" Background="{DynamicResource SystemControlForegroundBaseMediumLowBrush}" /> |
||||
|
|
||||
|
<Border Margin="12" |
||||
|
BorderBrush="{DynamicResource SystemControlForegroundBaseMediumLowBrush}" |
||||
|
BorderThickness="1" |
||||
|
CornerRadius="6" |
||||
|
ClipToBounds="True"> |
||||
|
<DrawerPage x:Name="DemoDrawer" |
||||
|
DrawerLayoutBehavior="Split" |
||||
|
DrawerBreakpointLength="500" |
||||
|
DrawerLength="200"> |
||||
|
<DrawerPage.Drawer> |
||||
|
<StackPanel Margin="8" Spacing="4"> |
||||
|
<Button HorizontalAlignment="Stretch" Background="Transparent" |
||||
|
Click="OnMenuItemClick" Tag="Home"> |
||||
|
<StackPanel Orientation="Horizontal" Spacing="8"> |
||||
|
<PathIcon Width="16" Height="16" |
||||
|
Data="M10,20V14H14V20H19V12H22L12,3L2,12H5V20H10Z" /> |
||||
|
<TextBlock Text="Home" VerticalAlignment="Center" /> |
||||
|
</StackPanel> |
||||
|
</Button> |
||||
|
<Button HorizontalAlignment="Stretch" Background="Transparent" |
||||
|
Click="OnMenuItemClick" Tag="Profile"> |
||||
|
<StackPanel Orientation="Horizontal" Spacing="8"> |
||||
|
<PathIcon Width="16" Height="16" |
||||
|
Data="M12,4A4,4 0 0,1 16,8A4,4 0 0,1 12,12A4,4 0 0,1 8,8A4,4 0 0,1 12,4M12,14C16.42,14 20,15.79 20,18V20H4V18C4,15.79 7.58,14 12,14Z" /> |
||||
|
<TextBlock Text="Profile" VerticalAlignment="Center" /> |
||||
|
</StackPanel> |
||||
|
</Button> |
||||
|
<Button HorizontalAlignment="Stretch" Background="Transparent" |
||||
|
Click="OnMenuItemClick" Tag="Settings"> |
||||
|
<StackPanel Orientation="Horizontal" Spacing="8"> |
||||
|
<PathIcon Width="16" Height="16" |
||||
|
Data="M12,15.5A3.5,3.5 0 0,1 8.5,12A3.5,3.5 0 0,1 12,8.5A3.5,3.5 0 0,1 15.5,12A3.5,3.5 0 0,1 12,15.5M19.43,12.97C19.47,12.65 19.5,12.33 19.5,12C19.5,11.67 19.47,11.34 19.43,11L21.54,9.37C21.73,9.22 21.78,8.95 21.66,8.73L19.66,5.27C19.54,5.05 19.27,4.96 19.05,5.05L16.56,6.05C16.04,5.66 15.5,5.32 14.87,5.07L14.5,2.42C14.46,2.18 14.25,2 14,2H10C9.75,2 9.54,2.18 9.5,2.42L9.13,5.07C8.5,5.32 7.96,5.66 7.44,6.05L4.95,5.05C4.73,4.96 4.46,5.05 4.34,5.27L2.34,8.73C2.21,8.95 2.27,9.22 2.46,9.37L4.57,11C4.53,11.34 4.5,11.67 4.57,12.97L2.46,14.63C2.27,14.78 2.21,15.05 2.34,15.27L4.34,18.73C4.46,18.95 4.73,19.04 4.95,18.95L7.44,17.94C7.96,18.34 8.5,18.68 9.13,18.93L9.5,21.58C9.54,21.82 9.75,22 10,22H14C14.25,22 14.46,21.82 14.5,21.58L14.87,18.93C15.5,18.68 16.04,18.34 16.56,17.94L19.05,18.95C19.27,19.04 19.54,18.95 19.66,18.73L21.66,15.27C21.78,15.05 21.73,14.78 21.54,14.63L19.43,12.97Z" /> |
||||
|
<TextBlock Text="Settings" VerticalAlignment="Center" /> |
||||
|
</StackPanel> |
||||
|
</Button> |
||||
|
</StackPanel> |
||||
|
</DrawerPage.Drawer> |
||||
|
<DrawerPage.Content> |
||||
|
<ContentPage x:Name="DetailPage" Header="Home"> |
||||
|
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center" Spacing="8"> |
||||
|
<TextBlock x:Name="DetailTitleText" Text="Home" FontSize="24" FontWeight="Bold" |
||||
|
HorizontalAlignment="Center" /> |
||||
|
<TextBlock Text="Select an item from the drawer." FontSize="13" Opacity="0.7" |
||||
|
TextWrapping="Wrap" TextAlignment="Center" MaxWidth="260" /> |
||||
|
</StackPanel> |
||||
|
</ContentPage> |
||||
|
</DrawerPage.Content> |
||||
|
</DrawerPage> |
||||
|
</Border> |
||||
|
</DockPanel> |
||||
|
</UserControl> |
||||
@ -0,0 +1,84 @@ |
|||||
|
using Avalonia.Controls; |
||||
|
using Avalonia.Controls.Primitives; |
||||
|
using Avalonia.Interactivity; |
||||
|
|
||||
|
namespace ControlCatalog.Pages |
||||
|
{ |
||||
|
public partial class DrawerPageBreakpointPage : UserControl |
||||
|
{ |
||||
|
private bool _isLoaded; |
||||
|
|
||||
|
public DrawerPageBreakpointPage() |
||||
|
{ |
||||
|
InitializeComponent(); |
||||
|
} |
||||
|
|
||||
|
protected override void OnLoaded(RoutedEventArgs e) |
||||
|
{ |
||||
|
base.OnLoaded(e); |
||||
|
_isLoaded = true; |
||||
|
DemoDrawer.PropertyChanged += OnDrawerPropertyChanged; |
||||
|
UpdateStatus(); |
||||
|
} |
||||
|
|
||||
|
protected override void OnUnloaded(RoutedEventArgs e) |
||||
|
{ |
||||
|
base.OnUnloaded(e); |
||||
|
DemoDrawer.PropertyChanged -= OnDrawerPropertyChanged; |
||||
|
} |
||||
|
|
||||
|
private void OnDrawerPropertyChanged(object? sender, Avalonia.AvaloniaPropertyChangedEventArgs e) |
||||
|
{ |
||||
|
if (e.Property == DrawerPage.BoundsProperty) |
||||
|
UpdateStatus(); |
||||
|
} |
||||
|
|
||||
|
private void OnBreakpointChanged(object? sender, RangeBaseValueChangedEventArgs e) |
||||
|
{ |
||||
|
if (!_isLoaded) |
||||
|
return; |
||||
|
var value = (int)e.NewValue; |
||||
|
DemoDrawer.DrawerBreakpointLength = value; |
||||
|
BreakpointText.Text = value.ToString(); |
||||
|
UpdateStatus(); |
||||
|
} |
||||
|
|
||||
|
private void OnLayoutChanged(object? sender, SelectionChangedEventArgs e) |
||||
|
{ |
||||
|
if (!_isLoaded) |
||||
|
return; |
||||
|
DemoDrawer.DrawerLayoutBehavior = LayoutCombo.SelectedIndex switch |
||||
|
{ |
||||
|
0 => DrawerLayoutBehavior.Split, |
||||
|
1 => DrawerLayoutBehavior.CompactInline, |
||||
|
2 => DrawerLayoutBehavior.CompactOverlay, |
||||
|
_ => DrawerLayoutBehavior.Split |
||||
|
}; |
||||
|
UpdateStatus(); |
||||
|
} |
||||
|
|
||||
|
private void OnMenuItemClick(object? sender, RoutedEventArgs e) |
||||
|
{ |
||||
|
if (!_isLoaded || sender is not Button button) |
||||
|
return; |
||||
|
var item = button.Tag?.ToString() ?? "Home"; |
||||
|
DetailTitleText.Text = item; |
||||
|
DetailPage.Header = item; |
||||
|
if (DemoDrawer.DrawerLayoutBehavior != DrawerLayoutBehavior.Split) |
||||
|
DemoDrawer.IsOpen = false; |
||||
|
} |
||||
|
|
||||
|
private void UpdateStatus() |
||||
|
{ |
||||
|
var isVertical = DemoDrawer.DrawerPlacement == DrawerPlacement.Top || |
||||
|
DemoDrawer.DrawerPlacement == DrawerPlacement.Bottom; |
||||
|
var length = isVertical ? DemoDrawer.Bounds.Height : DemoDrawer.Bounds.Width; |
||||
|
var breakpoint = DemoDrawer.DrawerBreakpointLength; |
||||
|
WidthText.Text = $"{(isVertical ? "Height" : "Width")}: {(int)length} px"; |
||||
|
var isOverlay = breakpoint > 0 && length > 0 && length < breakpoint; |
||||
|
ModeText.Text = isOverlay ? |
||||
|
"Mode: Overlay (below breakpoint)" : |
||||
|
$"Mode: {DemoDrawer.DrawerLayoutBehavior} (above breakpoint)"; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,95 @@ |
|||||
|
using System; |
||||
|
using System.Threading.Tasks; |
||||
|
using Avalonia.Controls; |
||||
|
using MiniMvvm; |
||||
|
|
||||
|
namespace ControlCatalog.Pages |
||||
|
{ |
||||
|
internal interface ISampleNavigationService |
||||
|
{ |
||||
|
event EventHandler<NavigationStateChangedEventArgs>? StateChanged; |
||||
|
|
||||
|
Task NavigateToAsync(ViewModelBase viewModel); |
||||
|
|
||||
|
Task GoBackAsync(); |
||||
|
|
||||
|
Task PopToRootAsync(); |
||||
|
} |
||||
|
|
||||
|
internal interface ISamplePageFactory |
||||
|
{ |
||||
|
ContentPage CreatePage(ViewModelBase viewModel); |
||||
|
} |
||||
|
|
||||
|
internal sealed class NavigationStateChangedEventArgs : EventArgs |
||||
|
{ |
||||
|
public NavigationStateChangedEventArgs(string currentPageHeader, int navigationDepth, string lastAction) |
||||
|
{ |
||||
|
CurrentPageHeader = currentPageHeader; |
||||
|
NavigationDepth = navigationDepth; |
||||
|
LastAction = lastAction; |
||||
|
} |
||||
|
|
||||
|
public string CurrentPageHeader { get; } |
||||
|
|
||||
|
public int NavigationDepth { get; } |
||||
|
|
||||
|
public string LastAction { get; } |
||||
|
} |
||||
|
|
||||
|
internal sealed class SampleNavigationService : ISampleNavigationService |
||||
|
{ |
||||
|
private readonly NavigationPage _navigationPage; |
||||
|
private readonly ISamplePageFactory _pageFactory; |
||||
|
|
||||
|
public SampleNavigationService(NavigationPage navigationPage, ISamplePageFactory pageFactory) |
||||
|
{ |
||||
|
_navigationPage = navigationPage; |
||||
|
_pageFactory = pageFactory; |
||||
|
|
||||
|
_navigationPage.Pushed += (_, e) => PublishState($"Pushed {e.Page?.Header}"); |
||||
|
_navigationPage.Popped += (_, e) => PublishState($"Popped {e.Page?.Header}"); |
||||
|
_navigationPage.PoppedToRoot += (_, _) => PublishState("Popped to root"); |
||||
|
} |
||||
|
|
||||
|
public event EventHandler<NavigationStateChangedEventArgs>? StateChanged; |
||||
|
|
||||
|
public async Task NavigateToAsync(ViewModelBase viewModel) |
||||
|
{ |
||||
|
var page = _pageFactory.CreatePage(viewModel); |
||||
|
await _navigationPage.PushAsync(page); |
||||
|
} |
||||
|
|
||||
|
public async Task GoBackAsync() |
||||
|
{ |
||||
|
if (_navigationPage.NavigationStack.Count <= 1) |
||||
|
{ |
||||
|
PublishState("Already at the root page"); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
await _navigationPage.PopAsync(); |
||||
|
} |
||||
|
|
||||
|
public async Task PopToRootAsync() |
||||
|
{ |
||||
|
if (_navigationPage.NavigationStack.Count <= 1) |
||||
|
{ |
||||
|
PublishState("Already at the root page"); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
await _navigationPage.PopToRootAsync(); |
||||
|
} |
||||
|
|
||||
|
private void PublishState(string lastAction) |
||||
|
{ |
||||
|
var header = _navigationPage.CurrentPage?.Header?.ToString() ?? "None"; |
||||
|
|
||||
|
StateChanged?.Invoke(this, new NavigationStateChangedEventArgs( |
||||
|
header, |
||||
|
_navigationPage.NavigationStack.Count, |
||||
|
lastAction)); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,86 @@ |
|||||
|
<UserControl xmlns="https://github.com/avaloniaui" |
||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" |
||||
|
xmlns:pages="using:ControlCatalog.Pages" |
||||
|
x:Class="ControlCatalog.Pages.NavigationPageMvvmPage" |
||||
|
x:DataType="pages:NavigationPageMvvmShellViewModel"> |
||||
|
<DockPanel> |
||||
|
<ScrollViewer DockPanel.Dock="Right" Width="300"> |
||||
|
<StackPanel Margin="12" Spacing="12"> |
||||
|
<TextBlock Text="MVVM Pattern" |
||||
|
FontSize="16" |
||||
|
FontWeight="SemiBold" |
||||
|
Foreground="{DynamicResource SystemControlHighlightAccentBrush}" /> |
||||
|
|
||||
|
<TextBlock TextWrapping="Wrap" |
||||
|
FontSize="12" |
||||
|
Opacity="0.75" |
||||
|
Text="This sample keeps NavigationPage in the view, sends commands from view models, routes push or pop operations through ISampleNavigationService, and resolves pages in a separate SamplePageFactory." /> |
||||
|
|
||||
|
<Separator /> |
||||
|
|
||||
|
<TextBlock Text="Selected Project" |
||||
|
FontSize="13" |
||||
|
FontWeight="SemiBold" /> |
||||
|
|
||||
|
<ListBox ItemsSource="{Binding Projects}" |
||||
|
SelectedItem="{Binding SelectedProject, Mode=TwoWay}" |
||||
|
MaxHeight="180"> |
||||
|
<ListBox.ItemTemplate> |
||||
|
<DataTemplate x:DataType="pages:ProjectCardViewModel"> |
||||
|
<StackPanel Margin="0,2" Spacing="2"> |
||||
|
<TextBlock Text="{Binding Name}" |
||||
|
FontWeight="SemiBold" /> |
||||
|
<TextBlock Text="{Binding Owner}" |
||||
|
FontSize="11" |
||||
|
Opacity="0.65" /> |
||||
|
</StackPanel> |
||||
|
</DataTemplate> |
||||
|
</ListBox.ItemTemplate> |
||||
|
</ListBox> |
||||
|
|
||||
|
<Button Content="Open Selected Project" |
||||
|
Command="{Binding OpenSelectedProjectCommand}" /> |
||||
|
<Button Content="Back" |
||||
|
Command="{Binding GoBackCommand}" /> |
||||
|
<Button Content="Pop To Root" |
||||
|
Command="{Binding PopToRootCommand}" /> |
||||
|
|
||||
|
<Separator /> |
||||
|
|
||||
|
<TextBlock Text="Navigation State" |
||||
|
FontSize="13" |
||||
|
FontWeight="SemiBold" /> |
||||
|
<TextBlock Text="{Binding CurrentPageHeader, StringFormat=Current page: {0}}" |
||||
|
Opacity="0.75" /> |
||||
|
<TextBlock Text="{Binding NavigationDepth, StringFormat=Stack depth: {0}}" |
||||
|
Opacity="0.75" /> |
||||
|
<TextBlock Text="{Binding LastAction, StringFormat=Last action: {0}}" |
||||
|
Opacity="0.75" |
||||
|
TextWrapping="Wrap" /> |
||||
|
|
||||
|
<Separator /> |
||||
|
|
||||
|
<TextBlock Text="Selected Details" |
||||
|
FontSize="13" |
||||
|
FontWeight="SemiBold" /> |
||||
|
<TextBlock Text="{Binding SelectedProject.Status, StringFormat=Status: {0}}" |
||||
|
Opacity="0.75" /> |
||||
|
<TextBlock Text="{Binding SelectedProject.NextMilestone, StringFormat=Next milestone: {0}}" |
||||
|
Opacity="0.75" |
||||
|
TextWrapping="Wrap" /> |
||||
|
</StackPanel> |
||||
|
</ScrollViewer> |
||||
|
|
||||
|
<Border DockPanel.Dock="Right" |
||||
|
Width="1" |
||||
|
Background="{DynamicResource SystemControlForegroundBaseMediumLowBrush}" /> |
||||
|
|
||||
|
<Border Margin="12" |
||||
|
BorderBrush="{DynamicResource SystemControlForegroundBaseMediumLowBrush}" |
||||
|
BorderThickness="1" |
||||
|
CornerRadius="6" |
||||
|
ClipToBounds="True"> |
||||
|
<NavigationPage x:Name="DemoNav" /> |
||||
|
</Border> |
||||
|
</DockPanel> |
||||
|
</UserControl> |
||||
@ -0,0 +1,32 @@ |
|||||
|
using Avalonia.Controls; |
||||
|
using Avalonia.Interactivity; |
||||
|
|
||||
|
namespace ControlCatalog.Pages |
||||
|
{ |
||||
|
public partial class NavigationPageMvvmPage : UserControl |
||||
|
{ |
||||
|
private readonly NavigationPageMvvmShellViewModel _viewModel; |
||||
|
private bool _initialized; |
||||
|
|
||||
|
public NavigationPageMvvmPage() |
||||
|
{ |
||||
|
InitializeComponent(); |
||||
|
|
||||
|
ISamplePageFactory pageFactory = new SamplePageFactory(); |
||||
|
ISampleNavigationService navigationService = new SampleNavigationService(DemoNav, pageFactory); |
||||
|
_viewModel = new NavigationPageMvvmShellViewModel(navigationService); |
||||
|
DataContext = _viewModel; |
||||
|
|
||||
|
Loaded += OnLoaded; |
||||
|
} |
||||
|
|
||||
|
private async void OnLoaded(object? sender, RoutedEventArgs e) |
||||
|
{ |
||||
|
if (_initialized) |
||||
|
return; |
||||
|
|
||||
|
_initialized = true; |
||||
|
await _viewModel.InitializeAsync(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,252 @@ |
|||||
|
using System; |
||||
|
using Avalonia; |
||||
|
using Avalonia.Controls; |
||||
|
using Avalonia.Controls.Templates; |
||||
|
using Avalonia.Layout; |
||||
|
using Avalonia.Media; |
||||
|
using MiniMvvm; |
||||
|
|
||||
|
namespace ControlCatalog.Pages |
||||
|
{ |
||||
|
internal sealed class SamplePageFactory : ISamplePageFactory |
||||
|
{ |
||||
|
public ContentPage CreatePage(ViewModelBase viewModel) => |
||||
|
viewModel switch |
||||
|
{ |
||||
|
WorkspaceViewModel workspace => CreateWorkspacePage(workspace), |
||||
|
ProjectDetailViewModel detail => CreateProjectDetailPage(detail), |
||||
|
ProjectActivityViewModel activity => CreateProjectActivityPage(activity), |
||||
|
_ => throw new InvalidOperationException($"Unsupported view model: {viewModel.GetType().Name}") |
||||
|
}; |
||||
|
|
||||
|
private static ContentPage CreateWorkspacePage(WorkspaceViewModel viewModel) |
||||
|
{ |
||||
|
var stack = new StackPanel |
||||
|
{ |
||||
|
Margin = new Thickness(20), |
||||
|
Spacing = 14, |
||||
|
}; |
||||
|
|
||||
|
stack.Children.Add(new TextBlock |
||||
|
{ |
||||
|
Text = viewModel.Title, |
||||
|
FontSize = 24, |
||||
|
FontWeight = FontWeight.Bold, |
||||
|
}); |
||||
|
stack.Children.Add(new TextBlock |
||||
|
{ |
||||
|
Text = viewModel.Description, |
||||
|
FontSize = 13, |
||||
|
Opacity = 0.75, |
||||
|
TextWrapping = TextWrapping.Wrap, |
||||
|
}); |
||||
|
|
||||
|
stack.Children.Add(new ItemsControl |
||||
|
{ |
||||
|
ItemsSource = viewModel.Projects, |
||||
|
ItemTemplate = new FuncDataTemplate<ProjectCardViewModel>((item, _) => |
||||
|
{ |
||||
|
if (item == null) |
||||
|
return new TextBlock(); |
||||
|
|
||||
|
var accentBrush = new SolidColorBrush(item.AccentColor); |
||||
|
var statusBadge = new Border |
||||
|
{ |
||||
|
Background = accentBrush, |
||||
|
CornerRadius = new CornerRadius(999), |
||||
|
Padding = new Thickness(10, 4), |
||||
|
Child = new TextBlock |
||||
|
{ |
||||
|
Text = item.Status, |
||||
|
Foreground = Brushes.White, |
||||
|
FontSize = 11, |
||||
|
FontWeight = FontWeight.SemiBold, |
||||
|
} |
||||
|
}; |
||||
|
DockPanel.SetDock(statusBadge, Dock.Right); |
||||
|
|
||||
|
var header = new DockPanel(); |
||||
|
header.Children.Add(statusBadge); |
||||
|
header.Children.Add(new TextBlock |
||||
|
{ |
||||
|
Text = item.Name, |
||||
|
FontSize = 17, |
||||
|
FontWeight = FontWeight.SemiBold, |
||||
|
}); |
||||
|
|
||||
|
return new Border |
||||
|
{ |
||||
|
Background = new SolidColorBrush(Color.FromArgb(20, item.AccentColor.R, item.AccentColor.G, item.AccentColor.B)), |
||||
|
BorderBrush = accentBrush, |
||||
|
BorderThickness = new Thickness(1), |
||||
|
CornerRadius = new CornerRadius(8), |
||||
|
Padding = new Thickness(14), |
||||
|
Margin = new Thickness(0, 0, 0, 8), |
||||
|
Child = new StackPanel |
||||
|
{ |
||||
|
Spacing = 8, |
||||
|
Children = |
||||
|
{ |
||||
|
header, |
||||
|
new TextBlock |
||||
|
{ |
||||
|
Text = item.Summary, |
||||
|
FontSize = 13, |
||||
|
Opacity = 0.72, |
||||
|
TextWrapping = TextWrapping.Wrap, |
||||
|
}, |
||||
|
new TextBlock |
||||
|
{ |
||||
|
Text = $"Owner: {item.Owner} • Next: {item.NextMilestone}", |
||||
|
FontSize = 12, |
||||
|
Opacity = 0.6, |
||||
|
TextWrapping = TextWrapping.Wrap, |
||||
|
}, |
||||
|
new Button |
||||
|
{ |
||||
|
Content = "Open Project", |
||||
|
HorizontalAlignment = HorizontalAlignment.Left, |
||||
|
Command = item.OpenCommand, |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
}; |
||||
|
}) |
||||
|
}); |
||||
|
|
||||
|
var page = new ContentPage |
||||
|
{ |
||||
|
Header = "Workspace", |
||||
|
Content = new ScrollViewer { Content = stack }, |
||||
|
HorizontalContentAlignment = HorizontalAlignment.Stretch, |
||||
|
VerticalContentAlignment = VerticalAlignment.Stretch, |
||||
|
}; |
||||
|
|
||||
|
NavigationPage.SetHasBackButton(page, false); |
||||
|
return page; |
||||
|
} |
||||
|
|
||||
|
private static ContentPage CreateProjectDetailPage(ProjectDetailViewModel viewModel) |
||||
|
{ |
||||
|
var accentBrush = new SolidColorBrush(viewModel.AccentColor); |
||||
|
var panel = new StackPanel |
||||
|
{ |
||||
|
Margin = new Thickness(24, 20), |
||||
|
Spacing = 12, |
||||
|
}; |
||||
|
|
||||
|
panel.Children.Add(new Border |
||||
|
{ |
||||
|
Background = accentBrush, |
||||
|
CornerRadius = new CornerRadius(999), |
||||
|
Padding = new Thickness(12, 5), |
||||
|
HorizontalAlignment = HorizontalAlignment.Left, |
||||
|
Child = new TextBlock |
||||
|
{ |
||||
|
Text = viewModel.Status, |
||||
|
Foreground = Brushes.White, |
||||
|
FontSize = 11, |
||||
|
FontWeight = FontWeight.SemiBold, |
||||
|
} |
||||
|
}); |
||||
|
panel.Children.Add(new TextBlock |
||||
|
{ |
||||
|
Text = viewModel.Name, |
||||
|
FontSize = 26, |
||||
|
FontWeight = FontWeight.Bold, |
||||
|
}); |
||||
|
panel.Children.Add(new TextBlock |
||||
|
{ |
||||
|
Text = viewModel.Summary, |
||||
|
FontSize = 14, |
||||
|
Opacity = 0.78, |
||||
|
TextWrapping = TextWrapping.Wrap, |
||||
|
}); |
||||
|
panel.Children.Add(new TextBlock |
||||
|
{ |
||||
|
Text = $"Owner: {viewModel.Owner}", |
||||
|
FontSize = 13, |
||||
|
Opacity = 0.68, |
||||
|
}); |
||||
|
panel.Children.Add(new TextBlock |
||||
|
{ |
||||
|
Text = $"Next milestone: {viewModel.NextMilestone}", |
||||
|
FontSize = 13, |
||||
|
Opacity = 0.68, |
||||
|
TextWrapping = TextWrapping.Wrap, |
||||
|
}); |
||||
|
panel.Children.Add(new Separator { Margin = new Thickness(0, 4) }); |
||||
|
panel.Children.Add(new TextBlock |
||||
|
{ |
||||
|
Text = "This page is resolved by SamplePageFactory from a ProjectDetailViewModel. The view model only requests navigation through ISampleNavigationService.", |
||||
|
FontSize = 12, |
||||
|
Opacity = 0.7, |
||||
|
TextWrapping = TextWrapping.Wrap, |
||||
|
}); |
||||
|
panel.Children.Add(new Button |
||||
|
{ |
||||
|
Content = "Open Activity", |
||||
|
HorizontalAlignment = HorizontalAlignment.Left, |
||||
|
Command = viewModel.OpenActivityCommand, |
||||
|
}); |
||||
|
|
||||
|
return new ContentPage |
||||
|
{ |
||||
|
Header = viewModel.Name, |
||||
|
Background = new SolidColorBrush(Color.FromArgb(18, viewModel.AccentColor.R, viewModel.AccentColor.G, viewModel.AccentColor.B)), |
||||
|
Content = new ScrollViewer { Content = panel }, |
||||
|
HorizontalContentAlignment = HorizontalAlignment.Stretch, |
||||
|
VerticalContentAlignment = VerticalAlignment.Stretch, |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
private static ContentPage CreateProjectActivityPage(ProjectActivityViewModel viewModel) |
||||
|
{ |
||||
|
var panel = new StackPanel |
||||
|
{ |
||||
|
Margin = new Thickness(24, 20), |
||||
|
Spacing = 10, |
||||
|
}; |
||||
|
|
||||
|
panel.Children.Add(new TextBlock |
||||
|
{ |
||||
|
Text = "Activity Timeline", |
||||
|
FontSize = 24, |
||||
|
FontWeight = FontWeight.Bold, |
||||
|
}); |
||||
|
panel.Children.Add(new TextBlock |
||||
|
{ |
||||
|
Text = $"Recent updates for {viewModel.Name}. This page was opened from a command on the detail view model.", |
||||
|
FontSize = 13, |
||||
|
Opacity = 0.74, |
||||
|
TextWrapping = TextWrapping.Wrap, |
||||
|
}); |
||||
|
|
||||
|
foreach (var item in viewModel.Items) |
||||
|
{ |
||||
|
panel.Children.Add(new Border |
||||
|
{ |
||||
|
Background = new SolidColorBrush(Color.FromArgb(14, viewModel.AccentColor.R, viewModel.AccentColor.G, viewModel.AccentColor.B)), |
||||
|
BorderBrush = new SolidColorBrush(Color.FromArgb(80, viewModel.AccentColor.R, viewModel.AccentColor.G, viewModel.AccentColor.B)), |
||||
|
BorderThickness = new Thickness(1), |
||||
|
CornerRadius = new CornerRadius(6), |
||||
|
Padding = new Thickness(12, 10), |
||||
|
Child = new TextBlock |
||||
|
{ |
||||
|
Text = item, |
||||
|
FontSize = 13, |
||||
|
TextWrapping = TextWrapping.Wrap, |
||||
|
} |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
return new ContentPage |
||||
|
{ |
||||
|
Header = "Activity", |
||||
|
Content = new ScrollViewer { Content = panel }, |
||||
|
HorizontalContentAlignment = HorizontalAlignment.Stretch, |
||||
|
VerticalContentAlignment = VerticalAlignment.Stretch, |
||||
|
}; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,238 @@ |
|||||
|
using System.Collections.Generic; |
||||
|
using System.Threading.Tasks; |
||||
|
using Avalonia.Media; |
||||
|
using MiniMvvm; |
||||
|
|
||||
|
namespace ControlCatalog.Pages |
||||
|
{ |
||||
|
public sealed class NavigationPageMvvmShellViewModel : ViewModelBase |
||||
|
{ |
||||
|
private readonly ISampleNavigationService _navigationService; |
||||
|
private string _currentPageHeader = "Not initialized"; |
||||
|
private string _lastAction = "Waiting for first load"; |
||||
|
private int _navigationDepth; |
||||
|
private ProjectCardViewModel? _selectedProject; |
||||
|
|
||||
|
internal NavigationPageMvvmShellViewModel(ISampleNavigationService navigationService) |
||||
|
{ |
||||
|
_navigationService = navigationService; |
||||
|
_navigationService.StateChanged += OnStateChanged; |
||||
|
|
||||
|
Workspace = new WorkspaceViewModel(CreateProjects(navigationService)); |
||||
|
SelectedProject = Workspace.Projects[0]; |
||||
|
|
||||
|
OpenSelectedProjectCommand = MiniCommand.CreateFromTask(OpenSelectedProjectAsync); |
||||
|
GoBackCommand = MiniCommand.CreateFromTask(_navigationService.GoBackAsync); |
||||
|
PopToRootCommand = MiniCommand.CreateFromTask(_navigationService.PopToRootAsync); |
||||
|
} |
||||
|
|
||||
|
internal WorkspaceViewModel Workspace { get; } |
||||
|
|
||||
|
public IReadOnlyList<ProjectCardViewModel> Projects => Workspace.Projects; |
||||
|
|
||||
|
public MiniCommand OpenSelectedProjectCommand { get; } |
||||
|
|
||||
|
public MiniCommand GoBackCommand { get; } |
||||
|
|
||||
|
public MiniCommand PopToRootCommand { get; } |
||||
|
|
||||
|
public string CurrentPageHeader |
||||
|
{ |
||||
|
get => _currentPageHeader; |
||||
|
set => this.RaiseAndSetIfChanged(ref _currentPageHeader, value); |
||||
|
} |
||||
|
|
||||
|
public int NavigationDepth |
||||
|
{ |
||||
|
get => _navigationDepth; |
||||
|
set => this.RaiseAndSetIfChanged(ref _navigationDepth, value); |
||||
|
} |
||||
|
|
||||
|
public string LastAction |
||||
|
{ |
||||
|
get => _lastAction; |
||||
|
set => this.RaiseAndSetIfChanged(ref _lastAction, value); |
||||
|
} |
||||
|
|
||||
|
public ProjectCardViewModel? SelectedProject |
||||
|
{ |
||||
|
get => _selectedProject; |
||||
|
set => this.RaiseAndSetIfChanged(ref _selectedProject, value); |
||||
|
} |
||||
|
|
||||
|
public Task InitializeAsync() => _navigationService.NavigateToAsync(Workspace); |
||||
|
|
||||
|
private async Task OpenSelectedProjectAsync() |
||||
|
{ |
||||
|
if (SelectedProject == null) |
||||
|
return; |
||||
|
|
||||
|
await SelectedProject.OpenCommandAsync(); |
||||
|
} |
||||
|
|
||||
|
private void OnStateChanged(object? sender, NavigationStateChangedEventArgs e) |
||||
|
{ |
||||
|
CurrentPageHeader = e.CurrentPageHeader; |
||||
|
NavigationDepth = e.NavigationDepth; |
||||
|
LastAction = e.LastAction; |
||||
|
} |
||||
|
|
||||
|
private static IReadOnlyList<ProjectCardViewModel> CreateProjects(ISampleNavigationService navigationService) => |
||||
|
new[] |
||||
|
{ |
||||
|
new ProjectCardViewModel( |
||||
|
"Release Radar", |
||||
|
"Marta Collins", |
||||
|
"Ready for QA", |
||||
|
"Coordinate the 11.0 release checklist and lock down the final regression window.", |
||||
|
"Freeze build on Friday", |
||||
|
Color.Parse("#0063B1"), |
||||
|
navigationService, |
||||
|
new[] |
||||
|
{ |
||||
|
"Release notes draft updated with accessibility fixes.", |
||||
|
"Package validation finished for desktop artifacts.", |
||||
|
"Remaining task, confirm browser smoke test coverage." |
||||
|
}), |
||||
|
new ProjectCardViewModel( |
||||
|
"Support Console", |
||||
|
"Jae Kim", |
||||
|
"Active Sprint", |
||||
|
"Consolidate customer incidents into a triage board and route them to platform owners.", |
||||
|
"Triage review in 2 hours", |
||||
|
Color.Parse("#0F7B0F"), |
||||
|
navigationService, |
||||
|
new[] |
||||
|
{ |
||||
|
"Five customer reports grouped under input routing.", |
||||
|
"Hotfix candidate approved for preview branch.", |
||||
|
"Awaiting macOS verification on native embed scenarios." |
||||
|
}), |
||||
|
new ProjectCardViewModel( |
||||
|
"Docs Refresh", |
||||
|
"Anika Patel", |
||||
|
"Needs Review", |
||||
|
"Refresh navigation samples and walkthrough docs so the gallery matches the current API.", |
||||
|
"Sample review tomorrow", |
||||
|
Color.Parse("#8E562E"), |
||||
|
navigationService, |
||||
|
new[] |
||||
|
{ |
||||
|
"NavigationPage sample matrix reviewed with design.", |
||||
|
"MVVM walkthrough draft linked from the docs backlog.", |
||||
|
"Outstanding task, capture one more screenshot for drawer navigation." |
||||
|
}), |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
internal sealed class WorkspaceViewModel : ViewModelBase |
||||
|
{ |
||||
|
public WorkspaceViewModel(IReadOnlyList<ProjectCardViewModel> projects) |
||||
|
{ |
||||
|
Projects = projects; |
||||
|
} |
||||
|
|
||||
|
public string Title => "Team Workspace"; |
||||
|
|
||||
|
public string Description => |
||||
|
"Each card is a project view model with its own command. The command asks ISampleNavigationService to navigate with the next view model, and SamplePageFactory resolves the matching ContentPage."; |
||||
|
|
||||
|
public IReadOnlyList<ProjectCardViewModel> Projects { get; } |
||||
|
} |
||||
|
|
||||
|
public sealed class ProjectCardViewModel : ViewModelBase |
||||
|
{ |
||||
|
private readonly ISampleNavigationService _navigationService; |
||||
|
|
||||
|
internal ProjectCardViewModel( |
||||
|
string name, |
||||
|
string owner, |
||||
|
string status, |
||||
|
string summary, |
||||
|
string nextMilestone, |
||||
|
Color accentColor, |
||||
|
ISampleNavigationService navigationService, |
||||
|
IReadOnlyList<string> activityItems) |
||||
|
{ |
||||
|
Name = name; |
||||
|
Owner = owner; |
||||
|
Status = status; |
||||
|
Summary = summary; |
||||
|
NextMilestone = nextMilestone; |
||||
|
AccentColor = accentColor; |
||||
|
ActivityItems = activityItems; |
||||
|
_navigationService = navigationService; |
||||
|
|
||||
|
OpenCommand = MiniCommand.CreateFromTask(OpenCommandAsync); |
||||
|
} |
||||
|
|
||||
|
public string Name { get; } |
||||
|
|
||||
|
public string Owner { get; } |
||||
|
|
||||
|
public string Status { get; } |
||||
|
|
||||
|
public string Summary { get; } |
||||
|
|
||||
|
public string NextMilestone { get; } |
||||
|
|
||||
|
public Color AccentColor { get; } |
||||
|
|
||||
|
public IReadOnlyList<string> ActivityItems { get; } |
||||
|
|
||||
|
public MiniCommand OpenCommand { get; } |
||||
|
|
||||
|
public Task OpenCommandAsync() |
||||
|
{ |
||||
|
return _navigationService.NavigateToAsync(new ProjectDetailViewModel(this, _navigationService)); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
internal sealed class ProjectDetailViewModel : ViewModelBase |
||||
|
{ |
||||
|
private readonly ProjectCardViewModel _project; |
||||
|
private readonly ISampleNavigationService _navigationService; |
||||
|
|
||||
|
public ProjectDetailViewModel(ProjectCardViewModel project, ISampleNavigationService navigationService) |
||||
|
{ |
||||
|
_project = project; |
||||
|
_navigationService = navigationService; |
||||
|
OpenActivityCommand = MiniCommand.CreateFromTask(OpenActivityAsync); |
||||
|
} |
||||
|
|
||||
|
public string Name => _project.Name; |
||||
|
|
||||
|
public string Owner => _project.Owner; |
||||
|
|
||||
|
public string Status => _project.Status; |
||||
|
|
||||
|
public string Summary => _project.Summary; |
||||
|
|
||||
|
public string NextMilestone => _project.NextMilestone; |
||||
|
|
||||
|
public Color AccentColor => _project.AccentColor; |
||||
|
|
||||
|
public MiniCommand OpenActivityCommand { get; } |
||||
|
|
||||
|
private Task OpenActivityAsync() |
||||
|
{ |
||||
|
return _navigationService.NavigateToAsync(new ProjectActivityViewModel(_project)); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
internal sealed class ProjectActivityViewModel : ViewModelBase |
||||
|
{ |
||||
|
public ProjectActivityViewModel(ProjectCardViewModel project) |
||||
|
{ |
||||
|
Name = project.Name; |
||||
|
AccentColor = project.AccentColor; |
||||
|
Items = project.ActivityItems; |
||||
|
} |
||||
|
|
||||
|
public string Name { get; } |
||||
|
|
||||
|
public Color AccentColor { get; } |
||||
|
|
||||
|
public IReadOnlyList<string> Items { get; } |
||||
|
} |
||||
|
} |
||||