mirror of
https://gitcode.com/gh_mirrors/se/Semi.Avalonia
synced 2026-04-08 10:16:35 +08:00
Implement Semi Design theme for page-based navigation controls (ContentPage / DrawerPage / NavigationPage / TabbedPage) (#766)
* Initial plan * Implement Semi Design theme for ContentPage, DrawerPage, NavigationPage, TabbedPage Co-authored-by: zdpcdt <54255897+zdpcdt@users.noreply.github.com> * fix: bind ItemsSource to Pages in TabControl of TabbedPage. * chore: split demo navigation pages. * demo: improve NavigationPage demo pages with interactive controls Co-authored-by: zdpcdt <54255897+zdpcdt@users.noreply.github.com> * fix: use comma-separated Padding syntax and remove trailing newline Co-authored-by: zdpcdt <54255897+zdpcdt@users.noreply.github.com> * feat: implement semi design theme for navigation controls in demo pages. * feat: enhance demo pages with foreground color for better visibility * feat: add back button visibility control and improve navigation page layout. * chore: remove DrawerPage unused static resources. * feat: add HighContrast resources for ContentPage, DrawerPage, NavigationPage, TabbedPage Co-authored-by: zdpcdt <54255897+zdpcdt@users.noreply.github.com> * feat: implement CardTabbedPage & ButtonTabbedPage themes. --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: zdpcdt <54255897+zdpcdt@users.noreply.github.com> Co-authored-by: Dong Bin <popmessiah@hotmail.com>
This commit is contained in:
54
demo/Semi.Avalonia.Demo/Pages/ContentPageDemo.axaml
Normal file
54
demo/Semi.Avalonia.Demo/Pages/ContentPageDemo.axaml
Normal file
@@ -0,0 +1,54 @@
|
||||
<UserControl
|
||||
x:Class="Semi.Avalonia.Demo.Pages.ContentPageDemo"
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
d:DesignHeight="600"
|
||||
d:DesignWidth="800"
|
||||
mc:Ignorable="d">
|
||||
<DockPanel>
|
||||
<ScrollViewer DockPanel.Dock="Right" Width="260">
|
||||
<StackPanel Margin="12" Spacing="8">
|
||||
<TextBlock Text="Configuration" FontWeight="SemiBold" FontSize="16"
|
||||
Foreground="{DynamicResource SemiColorText0}" />
|
||||
<TextBlock Text="ContentPage is the fundamental page type. It hosts a single piece of content and integrates with NavigationPage, TabbedPage, and CarouselPage. The Header property sets the navigation bar title."
|
||||
FontSize="12" Opacity="0.7" TextWrapping="Wrap" />
|
||||
|
||||
<Separator />
|
||||
|
||||
<TextBlock Text="Navigation" FontWeight="SemiBold" />
|
||||
<Button Content="Push Page" HorizontalAlignment="Stretch" Click="OnPush" />
|
||||
<Button Content="Pop Page" HorizontalAlignment="Stretch" Click="OnPop" />
|
||||
<Button Content="Pop to Root" HorizontalAlignment="Stretch" Click="OnPopToRoot" />
|
||||
|
||||
<Separator />
|
||||
|
||||
<TextBlock Text="Key Properties" FontWeight="SemiBold" />
|
||||
<TextBlock Text="• Header: nav bar title (string or Control)" FontSize="12" Opacity="0.8" TextWrapping="Wrap" />
|
||||
<TextBlock Text="• Content: any Avalonia control" FontSize="12" Opacity="0.8" TextWrapping="Wrap" />
|
||||
<TextBlock Text="• Background: page background brush" FontSize="12" Opacity="0.8" TextWrapping="Wrap" />
|
||||
<TextBlock Text="• HorizontalContentAlignment" FontSize="12" Opacity="0.8" />
|
||||
<TextBlock Text="• VerticalContentAlignment" FontSize="12" Opacity="0.8" />
|
||||
<TextBlock Text="• AutomaticallyApplySafeAreaPadding" FontSize="12" Opacity="0.8" />
|
||||
|
||||
<Separator />
|
||||
|
||||
<TextBlock Name="StatusText"
|
||||
Text="Depth: 1 | Current: Root Page"
|
||||
FontSize="11"
|
||||
Opacity="0.7" />
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
|
||||
<Border DockPanel.Dock="Right" Width="1" Background="{DynamicResource SemiColorBackground0}" />
|
||||
|
||||
<Border Margin="12"
|
||||
BorderBrush="{DynamicResource SemiColorBorder}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="6"
|
||||
ClipToBounds="True">
|
||||
<NavigationPage Name="DemoNav" />
|
||||
</Border>
|
||||
</DockPanel>
|
||||
</UserControl>
|
||||
93
demo/Semi.Avalonia.Demo/Pages/ContentPageDemo.axaml.cs
Normal file
93
demo/Semi.Avalonia.Demo/Pages/ContentPageDemo.axaml.cs
Normal file
@@ -0,0 +1,93 @@
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Interactivity;
|
||||
using Avalonia.Media;
|
||||
using Avalonia.Layout;
|
||||
|
||||
namespace Semi.Avalonia.Demo.Pages;
|
||||
|
||||
public partial class ContentPageDemo : UserControl
|
||||
{
|
||||
private static readonly Color[] PageColors =
|
||||
[
|
||||
Color.FromRgb(0xE3, 0xF2, 0xFD), // blue
|
||||
Color.FromRgb(0xF3, 0xE5, 0xF5), // purple
|
||||
Color.FromRgb(0xE8, 0xF5, 0xE9), // green
|
||||
Color.FromRgb(0xFF, 0xF8, 0xE1), // amber
|
||||
Color.FromRgb(0xFB, 0xE9, 0xE7), // deep orange
|
||||
];
|
||||
|
||||
private int _pageCount;
|
||||
|
||||
public ContentPageDemo()
|
||||
{
|
||||
InitializeComponent();
|
||||
Loaded += OnLoaded;
|
||||
}
|
||||
|
||||
private async void OnLoaded(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
await DemoNav.PushAsync(MakePage("Root Page", "ContentPage inside a NavigationPage.\nUse the options to navigate."));
|
||||
UpdateStatus();
|
||||
}
|
||||
|
||||
private async void OnPush(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
_pageCount++;
|
||||
await DemoNav.PushAsync(MakePage($"Page {_pageCount}", $"ContentPage #{_pageCount}.\nNavigate back using the back button."));
|
||||
UpdateStatus();
|
||||
}
|
||||
|
||||
private async void OnPop(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
await DemoNav.PopAsync();
|
||||
UpdateStatus();
|
||||
}
|
||||
|
||||
private async void OnPopToRoot(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
await DemoNav.PopToRootAsync();
|
||||
_pageCount = 0;
|
||||
UpdateStatus();
|
||||
}
|
||||
|
||||
private void UpdateStatus()
|
||||
{
|
||||
StatusText.Text = $"Depth: {DemoNav.StackDepth} | Current: {DemoNav.CurrentPage?.Header}";
|
||||
}
|
||||
|
||||
private ContentPage MakePage(string header, string body) =>
|
||||
new ContentPage
|
||||
{
|
||||
Header = header,
|
||||
Background = new SolidColorBrush(PageColors[_pageCount % PageColors.Length]),
|
||||
Content = new StackPanel
|
||||
{
|
||||
HorizontalAlignment = HorizontalAlignment.Center,
|
||||
VerticalAlignment = VerticalAlignment.Center,
|
||||
Spacing = 10,
|
||||
Children =
|
||||
{
|
||||
new TextBlock
|
||||
{
|
||||
Text = header,
|
||||
FontSize = 20,
|
||||
FontWeight = FontWeight.SemiBold,
|
||||
HorizontalAlignment = HorizontalAlignment.Center,
|
||||
Foreground = Brushes.Black,
|
||||
},
|
||||
new TextBlock
|
||||
{
|
||||
Text = body,
|
||||
FontSize = 13,
|
||||
Opacity = 0.7,
|
||||
TextWrapping = TextWrapping.Wrap,
|
||||
TextAlignment = TextAlignment.Center,
|
||||
MaxWidth = 260,
|
||||
Foreground = Brushes.Black,
|
||||
}
|
||||
}
|
||||
},
|
||||
HorizontalContentAlignment = HorizontalAlignment.Stretch,
|
||||
VerticalContentAlignment = VerticalAlignment.Stretch
|
||||
};
|
||||
}
|
||||
72
demo/Semi.Avalonia.Demo/Pages/DrawerPageDemo.axaml
Normal file
72
demo/Semi.Avalonia.Demo/Pages/DrawerPageDemo.axaml
Normal file
@@ -0,0 +1,72 @@
|
||||
<UserControl
|
||||
x:Class="Semi.Avalonia.Demo.Pages.DrawerPageDemo"
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
d:DesignHeight="700"
|
||||
d:DesignWidth="800"
|
||||
mc:Ignorable="d">
|
||||
<DockPanel>
|
||||
<ScrollViewer DockPanel.Dock="Right" Width="260">
|
||||
<StackPanel Margin="12" Spacing="8">
|
||||
<TextBlock Text="Configuration" FontWeight="SemiBold" FontSize="16"
|
||||
Foreground="{DynamicResource SemiColorText0}" />
|
||||
|
||||
<Button Content="Toggle Drawer"
|
||||
HorizontalAlignment="Stretch"
|
||||
Click="OnToggleDrawer" />
|
||||
|
||||
<Separator />
|
||||
|
||||
<CheckBox Name="GestureCheck"
|
||||
Content="Gesture Enabled"
|
||||
IsChecked="True"
|
||||
IsCheckedChanged="OnGestureChanged" />
|
||||
|
||||
<Separator />
|
||||
|
||||
<TextBlock Text="Status" FontWeight="SemiBold" FontSize="14" />
|
||||
<TextBlock Name="StatusText"
|
||||
Text="Drawer: Closed"
|
||||
Opacity="0.7"
|
||||
TextWrapping="Wrap" />
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
|
||||
<Border DockPanel.Dock="Right" Width="1" Background="{DynamicResource SemiColorBackground0}" />
|
||||
|
||||
<Border Margin="12"
|
||||
BorderBrush="{DynamicResource SemiColorBorder}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="6"
|
||||
ClipToBounds="True">
|
||||
<DrawerPage Name="DemoDrawer"
|
||||
Header="First Look"
|
||||
DrawerLength="250">
|
||||
<DrawerPage.DrawerHeader>
|
||||
<Border Padding="16" Background="{DynamicResource SemiColorPrimary}">
|
||||
<TextBlock Text="Menu" FontSize="18" FontWeight="SemiBold" Foreground="{DynamicResource SemiColorText0}" />
|
||||
</Border>
|
||||
</DrawerPage.DrawerHeader>
|
||||
<DrawerPage.Drawer>
|
||||
<ListBox Name="DrawerMenu" SelectionChanged="OnMenuSelectionChanged">
|
||||
<ListBoxItem Content="Home" />
|
||||
<ListBoxItem Content="Settings" />
|
||||
<ListBoxItem Content="Profile" />
|
||||
<ListBoxItem Content="About" />
|
||||
</ListBox>
|
||||
</DrawerPage.Drawer>
|
||||
<DrawerPage.Content>
|
||||
<ContentPage Header="Home">
|
||||
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center" Spacing="8">
|
||||
<TextBlock Text="Home Page" FontSize="20" FontWeight="SemiBold" HorizontalAlignment="Center" />
|
||||
<TextBlock Text="Swipe from the left edge or use the hamburger button to open the drawer."
|
||||
FontSize="13" Opacity="0.7" TextWrapping="Wrap" TextAlignment="Center" MaxWidth="300" />
|
||||
</StackPanel>
|
||||
</ContentPage>
|
||||
</DrawerPage.Content>
|
||||
</DrawerPage>
|
||||
</Border>
|
||||
</DockPanel>
|
||||
</UserControl>
|
||||
68
demo/Semi.Avalonia.Demo/Pages/DrawerPageDemo.axaml.cs
Normal file
68
demo/Semi.Avalonia.Demo/Pages/DrawerPageDemo.axaml.cs
Normal file
@@ -0,0 +1,68 @@
|
||||
using System;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Interactivity;
|
||||
using Avalonia.Layout;
|
||||
using Avalonia.Media;
|
||||
|
||||
namespace Semi.Avalonia.Demo.Pages;
|
||||
|
||||
public partial class DrawerPageDemo : UserControl
|
||||
{
|
||||
public DrawerPageDemo()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
protected override void OnLoaded(RoutedEventArgs e)
|
||||
{
|
||||
base.OnLoaded(e);
|
||||
DemoDrawer.Opened += OnDrawerStatusChanged;
|
||||
DemoDrawer.Closed += OnDrawerStatusChanged;
|
||||
}
|
||||
|
||||
protected override void OnUnloaded(RoutedEventArgs e)
|
||||
{
|
||||
base.OnUnloaded(e);
|
||||
DemoDrawer.Opened -= OnDrawerStatusChanged;
|
||||
DemoDrawer.Closed -= OnDrawerStatusChanged;
|
||||
}
|
||||
|
||||
private void OnDrawerStatusChanged(object? sender, EventArgs e) => UpdateStatus();
|
||||
|
||||
private void OnToggleDrawer(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
DemoDrawer.IsOpen = !DemoDrawer.IsOpen;
|
||||
}
|
||||
|
||||
private void OnGestureChanged(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
DemoDrawer.IsGestureEnabled = GestureCheck.IsChecked == true;
|
||||
}
|
||||
|
||||
private void OnMenuSelectionChanged(object? sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
if (DrawerMenu.SelectedItem is ListBoxItem item)
|
||||
{
|
||||
DemoDrawer.Content = new ContentPage
|
||||
{
|
||||
Header = item.Content?.ToString(),
|
||||
Content = new TextBlock
|
||||
{
|
||||
Text = $"{item.Content} page content",
|
||||
FontSize = 16,
|
||||
HorizontalAlignment = HorizontalAlignment.Center,
|
||||
VerticalAlignment = VerticalAlignment.Center,
|
||||
Foreground = Brushes.Black,
|
||||
},
|
||||
HorizontalContentAlignment = HorizontalAlignment.Stretch,
|
||||
VerticalContentAlignment = VerticalAlignment.Stretch
|
||||
};
|
||||
DemoDrawer.IsOpen = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateStatus()
|
||||
{
|
||||
StatusText.Text = $"Drawer: {(DemoDrawer.IsOpen ? "Open" : "Closed")}";
|
||||
}
|
||||
}
|
||||
66
demo/Semi.Avalonia.Demo/Pages/NavigationDemoHelper.cs
Normal file
66
demo/Semi.Avalonia.Demo/Pages/NavigationDemoHelper.cs
Normal file
@@ -0,0 +1,66 @@
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Layout;
|
||||
using Avalonia.Media;
|
||||
|
||||
namespace Semi.Avalonia.Demo.Pages;
|
||||
|
||||
/// <summary>
|
||||
/// Shared helpers for ControlCatalog demo pages.
|
||||
/// </summary>
|
||||
internal static class NavigationDemoHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// Pastel background brushes cycled by page index.
|
||||
/// </summary>
|
||||
internal static readonly IBrush[] PageBrushes =
|
||||
[
|
||||
new SolidColorBrush(Color.Parse("#BBDEFB")),
|
||||
new SolidColorBrush(Color.Parse("#C8E6C9")),
|
||||
new SolidColorBrush(Color.Parse("#FFE0B2")),
|
||||
new SolidColorBrush(Color.Parse("#E1BEE7")),
|
||||
new SolidColorBrush(Color.Parse("#FFCDD2")),
|
||||
new SolidColorBrush(Color.Parse("#B2EBF2"))
|
||||
];
|
||||
|
||||
internal static IBrush GetPageBrush(int index) =>
|
||||
PageBrushes[(index % PageBrushes.Length + PageBrushes.Length) % PageBrushes.Length];
|
||||
|
||||
/// <summary>
|
||||
/// Creates a simple demo ContentPage with a centered title and subtitle.
|
||||
/// </summary>
|
||||
internal static ContentPage MakePage(string header, string body, int colorIndex) =>
|
||||
new()
|
||||
{
|
||||
Header = header,
|
||||
Background = GetPageBrush(colorIndex),
|
||||
Content = new StackPanel
|
||||
{
|
||||
HorizontalAlignment = HorizontalAlignment.Center,
|
||||
VerticalAlignment = VerticalAlignment.Center,
|
||||
Spacing = 8,
|
||||
Children =
|
||||
{
|
||||
new TextBlock
|
||||
{
|
||||
Text = header,
|
||||
FontSize = 20,
|
||||
FontWeight = FontWeight.SemiBold,
|
||||
HorizontalAlignment = HorizontalAlignment.Center,
|
||||
Foreground = Brushes.Black,
|
||||
},
|
||||
new TextBlock
|
||||
{
|
||||
Text = body,
|
||||
FontSize = 13,
|
||||
Opacity = 0.7,
|
||||
TextWrapping = TextWrapping.Wrap,
|
||||
TextAlignment = TextAlignment.Center,
|
||||
MaxWidth = 260,
|
||||
Foreground = Brushes.Black,
|
||||
}
|
||||
}
|
||||
},
|
||||
HorizontalContentAlignment = HorizontalAlignment.Stretch,
|
||||
VerticalContentAlignment = VerticalAlignment.Stretch
|
||||
};
|
||||
}
|
||||
65
demo/Semi.Avalonia.Demo/Pages/NavigationPageDemo.axaml
Normal file
65
demo/Semi.Avalonia.Demo/Pages/NavigationPageDemo.axaml
Normal file
@@ -0,0 +1,65 @@
|
||||
<UserControl
|
||||
x:Class="Semi.Avalonia.Demo.Pages.NavigationPageDemo"
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
d:DesignHeight="700"
|
||||
d:DesignWidth="800"
|
||||
mc:Ignorable="d">
|
||||
<ScrollViewer>
|
||||
<DockPanel>
|
||||
<ScrollViewer DockPanel.Dock="Right" Width="260">
|
||||
<StackPanel Margin="12" Spacing="8">
|
||||
<TextBlock Text="Configuration" FontWeight="SemiBold" FontSize="16" />
|
||||
<TextBlock Text="Navigation" FontWeight="SemiBold" FontSize="13" />
|
||||
|
||||
<Button Content="Push Page"
|
||||
HorizontalAlignment="Stretch"
|
||||
Click="OnPush" />
|
||||
<Button Content="Pop"
|
||||
HorizontalAlignment="Stretch"
|
||||
Click="OnPop" />
|
||||
<Button Content="Pop to Root"
|
||||
HorizontalAlignment="Stretch"
|
||||
Click="OnPopToRoot" />
|
||||
|
||||
<Separator />
|
||||
|
||||
<TextBlock Text="Options" FontWeight="SemiBold" FontSize="14" />
|
||||
|
||||
<CheckBox Name="HasNavBarCheck"
|
||||
Content="Has Navigation Bar"
|
||||
IsChecked="True"
|
||||
IsCheckedChanged="OnHasNavBarChanged" />
|
||||
<CheckBox Name="HasBackButtonCheck"
|
||||
Content="Has Back Button"
|
||||
IsChecked="True"
|
||||
IsCheckedChanged="OnHasBackButonChanged" />
|
||||
|
||||
<Separator />
|
||||
|
||||
<TextBlock Text="Status" FontWeight="SemiBold" FontSize="14" />
|
||||
<TextBlock Name="StatusText"
|
||||
Text="Depth: 1"
|
||||
Opacity="0.7"
|
||||
TextWrapping="Wrap" />
|
||||
<TextBlock Name="HeaderText"
|
||||
Text="Current: Home"
|
||||
Opacity="0.7"
|
||||
TextWrapping="Wrap" />
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
|
||||
<Border DockPanel.Dock="Right" Width="1" Background="{DynamicResource SemiColorBackground0}" />
|
||||
|
||||
<Border Margin="12"
|
||||
BorderBrush="{DynamicResource SemiColorBorder}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="6"
|
||||
ClipToBounds="True">
|
||||
<NavigationPage Name="DemoNav" />
|
||||
</Border>
|
||||
</DockPanel>
|
||||
</ScrollViewer>
|
||||
</UserControl>
|
||||
66
demo/Semi.Avalonia.Demo/Pages/NavigationPageDemo.axaml.cs
Normal file
66
demo/Semi.Avalonia.Demo/Pages/NavigationPageDemo.axaml.cs
Normal file
@@ -0,0 +1,66 @@
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Interactivity;
|
||||
|
||||
namespace Semi.Avalonia.Demo.Pages;
|
||||
|
||||
public partial class NavigationPageDemo : UserControl
|
||||
{
|
||||
private int _pageCount;
|
||||
|
||||
public NavigationPageDemo()
|
||||
{
|
||||
InitializeComponent();
|
||||
Loaded += OnLoaded;
|
||||
}
|
||||
|
||||
private async void OnLoaded(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
await DemoNav.PushAsync(NavigationDemoHelper.MakePage("Home", "Welcome!\nUse the buttons to push and pop pages.", 0), null);
|
||||
UpdateStatus();
|
||||
}
|
||||
|
||||
private async void OnPush(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
_pageCount++;
|
||||
var page = NavigationDemoHelper.MakePage($"Page {_pageCount}", $"This is page {_pageCount}.", _pageCount);
|
||||
NavigationPage.SetHasNavigationBar(page, HasNavBarCheck.IsChecked == true);
|
||||
NavigationPage.SetHasBackButton(page, HasBackButtonCheck.IsChecked == true);
|
||||
await DemoNav.PushAsync(page);
|
||||
UpdateStatus();
|
||||
}
|
||||
|
||||
private async void OnPop(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
await DemoNav.PopAsync();
|
||||
UpdateStatus();
|
||||
}
|
||||
|
||||
private async void OnPopToRoot(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
await DemoNav.PopToRootAsync();
|
||||
_pageCount = 0;
|
||||
UpdateStatus();
|
||||
}
|
||||
|
||||
private void OnHasNavBarChanged(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
if (DemoNav == null)
|
||||
return;
|
||||
if (DemoNav.CurrentPage != null)
|
||||
NavigationPage.SetHasNavigationBar(DemoNav.CurrentPage, HasNavBarCheck.IsChecked == true);
|
||||
}
|
||||
|
||||
private void OnHasBackButonChanged(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
if (DemoNav == null)
|
||||
return;
|
||||
if (DemoNav.CurrentPage != null)
|
||||
NavigationPage.SetHasBackButton(DemoNav.CurrentPage, HasBackButtonCheck.IsChecked == true);
|
||||
}
|
||||
|
||||
private void UpdateStatus()
|
||||
{
|
||||
StatusText.Text = $"Depth: {DemoNav.StackDepth}";
|
||||
HeaderText.Text = $"Current: {DemoNav.CurrentPage?.Header ?? "(none)"}";
|
||||
}
|
||||
}
|
||||
80
demo/Semi.Avalonia.Demo/Pages/TabbedPageDemo.axaml
Normal file
80
demo/Semi.Avalonia.Demo/Pages/TabbedPageDemo.axaml
Normal file
@@ -0,0 +1,80 @@
|
||||
<UserControl
|
||||
x:Class="Semi.Avalonia.Demo.Pages.TabbedPageDemo"
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
d:DesignHeight="600"
|
||||
d:DesignWidth="800"
|
||||
mc:Ignorable="d">
|
||||
<DockPanel>
|
||||
<ScrollViewer DockPanel.Dock="Right" Width="260">
|
||||
<StackPanel Margin="12" Spacing="8">
|
||||
<TextBlock Text="Configuration" FontWeight="SemiBold" FontSize="16"
|
||||
Foreground="{DynamicResource SemiColorText0}" />
|
||||
|
||||
<TextBlock Text="Tab Management" FontWeight="SemiBold" FontSize="13" />
|
||||
<StackPanel Spacing="6">
|
||||
<Button Content="Add Tab" Click="OnAddTab" HorizontalAlignment="Stretch" />
|
||||
<Button Content="Remove Latest Tab" Click="OnRemoveTab" HorizontalAlignment="Stretch" />
|
||||
</StackPanel>
|
||||
|
||||
<Separator />
|
||||
|
||||
<TextBlock Text="Tab Placement" FontWeight="SemiBold" FontSize="13" />
|
||||
<ComboBox Name="PlacementCombo" SelectedIndex="0"
|
||||
SelectionChanged="OnPlacementChanged" HorizontalAlignment="Stretch">
|
||||
<ComboBoxItem Content="Top" />
|
||||
<ComboBoxItem Content="Bottom" />
|
||||
<ComboBoxItem Content="Left" />
|
||||
<ComboBoxItem Content="Right" />
|
||||
</ComboBox>
|
||||
|
||||
<Separator />
|
||||
|
||||
<TextBlock Text="Status" FontWeight="SemiBold" FontSize="14" />
|
||||
<TextBlock Name="StatusText"
|
||||
Text="3 tabs | Selected: Home (0)"
|
||||
Opacity="0.7"
|
||||
TextWrapping="Wrap" />
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
|
||||
<Border DockPanel.Dock="Right" Width="1" Background="{DynamicResource SemiColorBackground0}" />
|
||||
|
||||
<Border Margin="12"
|
||||
BorderBrush="{DynamicResource SemiColorBorder}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="6"
|
||||
ClipToBounds="True">
|
||||
<TabbedPage Name="DemoTabs"
|
||||
TabPlacement="Top"
|
||||
SelectionChanged="OnSelectionChanged">
|
||||
<ContentPage Header="Home">
|
||||
<StackPanel Margin="16" Spacing="8">
|
||||
<TextBlock Text="Home Tab" FontSize="24" FontWeight="Bold" />
|
||||
<TextBlock Text="Welcome to the Home tab. This is a TabbedPage sample."
|
||||
TextWrapping="Wrap" />
|
||||
<TextBlock Text="Use the panel on the right to add or remove tabs dynamically."
|
||||
TextWrapping="Wrap" Opacity="0.7" />
|
||||
</StackPanel>
|
||||
</ContentPage>
|
||||
<ContentPage Header="Search">
|
||||
<StackPanel Margin="16" Spacing="8">
|
||||
<TextBlock Text="Search Tab" FontSize="24" FontWeight="Bold" />
|
||||
<TextBox PlaceholderText="Type to search..." />
|
||||
<TextBlock Text="Search results will appear here." Opacity="0.7" />
|
||||
</StackPanel>
|
||||
</ContentPage>
|
||||
<ContentPage Header="Settings">
|
||||
<StackPanel Margin="16" Spacing="8">
|
||||
<TextBlock Text="Settings Tab" FontSize="24" FontWeight="Bold" />
|
||||
<CheckBox Content="Enable notifications" />
|
||||
<CheckBox Content="Dark mode" />
|
||||
<CheckBox Content="Auto-save" IsChecked="True" />
|
||||
</StackPanel>
|
||||
</ContentPage>
|
||||
</TabbedPage>
|
||||
</Border>
|
||||
</DockPanel>
|
||||
</UserControl>
|
||||
84
demo/Semi.Avalonia.Demo/Pages/TabbedPageDemo.axaml.cs
Normal file
84
demo/Semi.Avalonia.Demo/Pages/TabbedPageDemo.axaml.cs
Normal file
@@ -0,0 +1,84 @@
|
||||
using System.Collections;
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Interactivity;
|
||||
using Avalonia.Media;
|
||||
|
||||
namespace Semi.Avalonia.Demo.Pages;
|
||||
|
||||
public partial class TabbedPageDemo : UserControl
|
||||
{
|
||||
private int _tabCounter = 3;
|
||||
|
||||
public TabbedPageDemo()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void OnAddTab(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
var idx = ++_tabCounter;
|
||||
var page = new ContentPage
|
||||
{
|
||||
Header = $"Tab {idx}",
|
||||
Content = new StackPanel
|
||||
{
|
||||
Margin = new Thickness(16),
|
||||
Spacing = 8,
|
||||
Children =
|
||||
{
|
||||
new TextBlock
|
||||
{
|
||||
Text = $"Tab {idx}",
|
||||
FontSize = 24,
|
||||
FontWeight = FontWeight.Bold,
|
||||
},
|
||||
new TextBlock
|
||||
{
|
||||
Text = $"This tab was added dynamically (tab #{idx}).",
|
||||
Opacity = 0.7,
|
||||
TextWrapping = TextWrapping.Wrap,
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
((IList)DemoTabs.Pages!).Add(page);
|
||||
UpdateStatus();
|
||||
}
|
||||
|
||||
private void OnRemoveTab(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
var pages = (IList)DemoTabs.Pages!;
|
||||
if (pages.Count > 1)
|
||||
{
|
||||
pages.RemoveAt(pages.Count - 1);
|
||||
UpdateStatus();
|
||||
}
|
||||
}
|
||||
|
||||
private void OnPlacementChanged(object? sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
if (DemoTabs == null) return;
|
||||
DemoTabs.TabPlacement = PlacementCombo.SelectedIndex switch
|
||||
{
|
||||
1 => TabPlacement.Bottom,
|
||||
2 => TabPlacement.Left,
|
||||
3 => TabPlacement.Right,
|
||||
_ => TabPlacement.Top
|
||||
};
|
||||
}
|
||||
|
||||
private void OnSelectionChanged(object? sender, PageSelectionChangedEventArgs e)
|
||||
{
|
||||
UpdateStatus();
|
||||
}
|
||||
|
||||
private void UpdateStatus()
|
||||
{
|
||||
if (StatusText == null) return;
|
||||
var pages = (IList)DemoTabs.Pages!;
|
||||
var pageName = (DemoTabs.SelectedPage as ContentPage)?.Header?.ToString() ?? "—";
|
||||
StatusText.Text = $"{pages.Count} tab{(pages.Count != 1 ? "s" : "")} | Selected: {pageName} ({DemoTabs.SelectedIndex})";
|
||||
}
|
||||
}
|
||||
@@ -215,6 +215,18 @@
|
||||
<TabItem
|
||||
Theme="{DynamicResource CategoryTabItem}"
|
||||
Header="Navigation" />
|
||||
<TabItem Header="ContentPage">
|
||||
<pages:ContentPageDemo />
|
||||
</TabItem>
|
||||
<TabItem Header="DrawerPage">
|
||||
<pages:DrawerPageDemo />
|
||||
</TabItem>
|
||||
<TabItem Header="NavigationPage">
|
||||
<pages:NavigationPageDemo />
|
||||
</TabItem>
|
||||
<TabItem Header="TabbedPage">
|
||||
<pages:TabbedPageDemo />
|
||||
</TabItem>
|
||||
<TabItem Header="TabControl">
|
||||
<pages:TabControlDemo />
|
||||
</TabItem>
|
||||
|
||||
Reference in New Issue
Block a user