Browse Source

Update ControlCatalog Sidebar design. (#22080)

* ControlCatalog - Side bar improvements

* adjust side bar icon to adapt with side bar size

* update sidebar colors

* add custom title bar decorations to control catalog

* share view code between home page and section page

* improve side bar selection state visual

* drop custom search bar in title decorations
pull/22015/merge
Emmanuel Hansen 1 week ago
committed by GitHub
parent
commit
0b713f27b6
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 6
      samples/ControlCatalog/App.xaml
  2. 103
      samples/ControlCatalog/Controls/HomeItemExpander.cs
  3. 52
      samples/ControlCatalog/Controls/SectionControl.axaml
  4. 25
      samples/ControlCatalog/Controls/SectionControl.axaml.cs
  5. 79
      samples/ControlCatalog/Controls/SelectableButton.cs
  6. 359
      samples/ControlCatalog/CustomThemes.xaml
  7. 36
      samples/ControlCatalog/Icons.cs
  8. 269
      samples/ControlCatalog/MainView.xaml
  9. 69
      samples/ControlCatalog/MainView.xaml.cs
  10. 18
      samples/ControlCatalog/MainWindow.xaml
  11. 28
      samples/ControlCatalog/Models/HomeSection.cs
  12. 16
      samples/ControlCatalog/Models/PageItem.cs
  13. 101
      samples/ControlCatalog/NavHeaderItem.xaml
  14. 92
      samples/ControlCatalog/Pages/HomePage.xaml
  15. 15
      samples/ControlCatalog/Pages/SectionPage.axaml
  16. 23
      samples/ControlCatalog/Pages/SectionPage.axaml.cs
  17. 150
      samples/ControlCatalog/Pages/SettingsPage.axaml
  18. 93
      samples/ControlCatalog/Pages/SettingsPage.axaml.cs
  19. 34
      samples/ControlCatalog/ScrollPage.xaml
  20. 157
      samples/ControlCatalog/ViewModels/MainWindowViewModel.cs
  21. 43
      samples/ControlCatalog/ViewModels/MainWindowViewModel_PageList.cs
  22. 10
      samples/ControlCatalog/ViewModels/SectionViewModel.cs
  23. 57
      samples/ControlCatalog/ViewModels/SettingsViewModel.cs

6
samples/ControlCatalog/App.xaml

@ -8,8 +8,7 @@
<ResourceDictionary>
<!-- Custom controls defined in other assemblies -->
<ResourceDictionary.MergedDictionaries>
<ResourceInclude Source="avares://ControlCatalog/ScrollPage.xaml"/>
<ResourceInclude Source="avares://ControlCatalog/NavHeaderItem.xaml"/>
<ResourceInclude Source="avares://ControlCatalog/CustomThemes.xaml"/>
</ResourceDictionary.MergedDictionaries>
<!-- Resources used only in the control catalog -->
@ -28,6 +27,9 @@
</ResourceDictionary>
</ResourceDictionary.ThemeDictionaries>
<StreamGeometry x:Key="SearchIcon">M10 2.5a7.5 7.5 0 0 1 5.964 12.048l4.743 4.745a1 1 0 0 1-1.32 1.497l-.094-.083-4.745-4.743A7.5 7.5 0 1 1 10 2.5Zm0 2a5.5 5.5 0 1 0 0 11 5.5 5.5 0 0 0 0-11Z</StreamGeometry>
<StreamGeometry x:Key="AppIcon">M24 0C37.2548 0 48 10.7452 48 24V42C48 45.3137 45.3137 48 42 48H24C10.7452 48 0 37.2548 0 24C0 10.7452 10.7452 0 24 0ZM24 7C16.3489 7 9.87832 12.0545 7.74496 19.0065C10.3931 19.1342 12.5 21.321 12.5 24C12.5 26.6793 10.3926 28.8664 7.74496 28.9941C9.83517 35.8054 16.0901 40.7958 23.5395 40.9939C26.6226 40.9252 29.1092 40.2605 31 39V41H41V24C41 14.827 33.7348 7.35088 24.6446 7.012L24.323 7.00301L24 7ZM24 16C28.4183 16 32 19.5817 32 24C32 28.4183 28.4183 32 24 32C19.5817 32 16 28.4183 16 24C16 19.5817 19.5817 16 24 16ZM7.5 20.5C5.567 20.5 4 22.067 4 24C4 25.933 5.567 27.5 7.5 27.5C9.433 27.5 11 25.933 11 24C11 22.067 9.433 20.5 7.5 20.5Z</StreamGeometry>
<!-- Styles attached dynamically depending on current theme (simple or fluent) -->
<FluentTheme x:Key="FluentTheme" />
<SimpleTheme x:Key="SimpleTheme" />

103
samples/ControlCatalog/Controls/HomeItemExpander.cs

@ -0,0 +1,103 @@
using System.Windows.Input;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Primitives;
using Avalonia.Data;
namespace ControlCatalog.Controls
{
public class HomeItemExpander : Expander, ISelectable
{
/// <summary>
/// Defines the <see cref="Command"/> property.
/// </summary>
public static readonly StyledProperty<ICommand?> CommandProperty =
Button.CommandProperty.AddOwner<HomeItemExpander>();
/// <summary>
/// Defines the <see cref="CommandParameter"/> property.
/// </summary>
public static readonly StyledProperty<object?> CommandParameterProperty =
Button.CommandParameterProperty.AddOwner<HomeItemExpander>();
/// <summary>
/// Defines the <see cref="CanExpand"/> property.
/// </summary>
public static readonly StyledProperty<bool> CanExpandProperty =
AvaloniaProperty.Register<HomeItemExpander, bool>(
nameof(CanExpand),
defaultBindingMode: BindingMode.TwoWay);
/// <summary>
/// Defines the <see cref="CanExpand"/> property.
/// </summary>
public static readonly DirectProperty<HomeItemExpander, bool> IsEffectivelyExpandedProperty =
AvaloniaProperty.RegisterDirect<HomeItemExpander, bool>(
nameof(IsEffectivelyExpanded),
x => x.IsEffectivelyExpanded,
(x, o) => x.IsEffectivelyExpanded = o,
defaultBindingMode: BindingMode.TwoWay);
/// <summary>
/// Defines the <see cref="IsSelected"/> property.
/// </summary>
public static readonly StyledProperty<bool> IsSelectedProperty =
SelectingItemsControl.IsSelectedProperty.AddOwner<HomeItemExpander>();
/// <summary>
/// Gets or sets an <see cref="ICommand"/> to be invoked when the button is clicked.
/// </summary>
public ICommand? Command
{
get => GetValue(CommandProperty);
set => SetValue(CommandProperty, value);
}
/// <summary>
/// Gets or sets a parameter to be passed to the <see cref="Command"/>.
/// </summary>
public object? CommandParameter
{
get => GetValue(CommandParameterProperty);
set => SetValue(CommandParameterProperty, value);
}
/// <summary>
/// Gets or sets a value indicating whether the <see cref="HomeItemExpander"/>
/// content area is open and visible.
/// </summary>
public bool CanExpand
{
get => GetValue(CanExpandProperty);
set => SetValue(CanExpandProperty, value);
}
/// <summary>
/// Gets or sets the selection state of the item.
/// </summary>
public bool IsSelected
{
get => GetValue(IsSelectedProperty);
set => SetValue(IsSelectedProperty, value);
}
/// <summary>
/// Gets whether the <see cref="HomeItemExpander"/> is expanded
/// </summary>
public bool IsEffectivelyExpanded
{
get => field;
private set => SetAndRaise(IsEffectivelyExpandedProperty, ref field, value);
}
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
{
base.OnPropertyChanged(change);
if (change.Property == CanExpandProperty || change.Property == IsExpandedProperty)
{
IsEffectivelyExpanded = CanExpand && IsExpanded;
}
}
}
}

52
samples/ControlCatalog/Controls/SectionControl.axaml

@ -0,0 +1,52 @@
<UserControl 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"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
xmlns:models="clr-namespace:ControlCatalog.Models"
xmlns:controlCatalog="using:ControlCatalog"
xmlns:viewModels="using:ControlCatalog.ViewModels"
x:DataType="models:HomeSection"
x:Class="ControlCatalog.Controls.SectionControl">
<StackPanel Margin="0,0,0,26">
<ItemsControl ItemsSource="{Binding Items}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid RowSpacing="12" ColumnSpacing="12"
Margin="0, 0, 1, 0"
SizeChanged="UniformGrid_OnSizeChanged" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate DataType="models:PageItem">
<Button Theme="{StaticResource ButtonCardTheme}"
Command="{Binding $parent[controlCatalog:MainView].((viewModels:MainWindowViewModel)DataContext).NavigateToPageCommand}"
CommandParameter="{Binding}">
<StackPanel Spacing="10">
<Border Background="{DynamicResource HomeBadgeBackground}"
CornerRadius="8"
Width="36" Height="36"
HorizontalAlignment="Left">
<PathIcon Data="{Binding IconData}"
Foreground="{DynamicResource HomeBadgeForeground}"
Width="18" Height="18"
HorizontalAlignment="Center"
VerticalAlignment="Center" />
</Border>
<StackPanel Spacing="3">
<TextBlock Text="{Binding Header}"
FontSize="14" FontWeight="SemiBold" />
<TextBlock Text="{Binding Description}"
FontSize="12"
Foreground="{DynamicResource HomeSubtleForeground}"
TextWrapping="Wrap"
TextTrimming="CharacterEllipsis"
MaxLines="2" />
</StackPanel>
</StackPanel>
</Button>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</UserControl>

25
samples/ControlCatalog/Controls/SectionControl.axaml.cs

@ -0,0 +1,25 @@
using System;
using Avalonia.Controls;
using Avalonia.Controls.Primitives;
namespace ControlCatalog.Controls
{
public partial class SectionControl : UserControl
{
public SectionControl()
{
InitializeComponent();
}
private void UniformGrid_OnSizeChanged(object? sender, SizeChangedEventArgs e)
{
if (sender is not UniformGrid grid)
return;
const int minItemWidth = 248;
grid.Columns = Math.Max(
1,
(int)((e.NewSize.Width + grid.ColumnSpacing) / (minItemWidth + grid.ColumnSpacing)));
}
}
}

79
samples/ControlCatalog/Controls/SelectableButton.cs

@ -0,0 +1,79 @@
using System;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Metadata;
using Avalonia.Controls.Primitives;
using Avalonia.Data;
using Avalonia.Interactivity;
namespace ControlCatalog.Controls
{
[PseudoClasses(":selected")]
public class SelectableButton : ToggleButton, ISelectable
{
/// <summary>
/// Defines the <see cref="IsSelected"/> property.
/// </summary>
public static readonly StyledProperty<bool> IsSelectedProperty =
AvaloniaProperty.Register<SelectableButton, bool>(nameof(IsSelected), false,
defaultBindingMode: BindingMode.TwoWay);
/// <summary>
/// Defines the <see cref="IsSelectedChanged"/> event.
/// </summary>
public static readonly RoutedEvent<RoutedEventArgs> IsSelectedChangedEvent =
RoutedEvent.Register<SelectableButton, RoutedEventArgs>(
nameof(IsSelectedChanged),
RoutingStrategies.Bubble);
public SelectableButton()
{
UpdatePseudoClasses(IsSelected);
}
/// <summary>
/// Gets or sets whether the <see cref="SelectableButton"/> is selected.
/// </summary>
public bool IsSelected
{
get => GetValue(IsSelectedProperty);
set => SetValue(IsSelectedProperty, value);
}
/// <summary>
/// Raised when the <see cref="IsSelected"/> property value changes.
/// </summary>
public event EventHandler<RoutedEventArgs>? IsSelectedChanged
{
add => AddHandler(IsSelectedChangedEvent, value);
remove => RemoveHandler(IsSelectedChangedEvent, value);
}
/// <inheritdoc/>
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
{
base.OnPropertyChanged(change);
if (change.Property == IsSelectedProperty)
{
var newValue = change.GetNewValue<bool>();
UpdatePseudoClasses(newValue);
OnIsSelectedChanged(new RoutedEventArgs(IsSelectedChangedEvent));
}
}
private void UpdatePseudoClasses(bool isSelected)
{
PseudoClasses.Set(":selected", isSelected);
}
/// <summary>
/// Called when <see cref="IsSelected"/> changes.
/// </summary>
/// <param name="e">Event arguments for the routed event that is raised by the default implementation of this method.</param>
protected virtual void OnIsSelectedChanged(RoutedEventArgs e)
{
RaiseEvent(e);
}
}
}

359
samples/ControlCatalog/CustomThemes.xaml

@ -0,0 +1,359 @@
<ResourceDictionary xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="using:ControlCatalog.Controls">
<ResourceDictionary.ThemeDictionaries>
<ResourceDictionary x:Key="Dark">
<Color x:Key="HamburgerBaseHighColor">#99FFFFFF</Color>
<Color x:Key="HamburgerChromeMediumColor">#FF1F1F1F</Color>
<Color x:Key="HamburgerAltHighColor">#FF000000</Color>
<Color x:Key="HamburgerChromeLowColor">#FF171717</Color>
<SolidColorBrush x:Key="HomeCardBackground" Color="#2B2B33" />
<SolidColorBrush x:Key="HomeCardBorderBrush" Color="#3A3A45" />
<SolidColorBrush x:Key="HomeCardBorderBrushHover" Color="#8AB4FF" />
<SolidColorBrush x:Key="HomeSubtleForeground" Color="#9C9CAB" />
<SolidColorBrush x:Key="HomeBadgeBackground" Color="#31395A" />
<SolidColorBrush x:Key="HomeBadgeForeground" Color="#8AB4FF" />
</ResourceDictionary>
<ResourceDictionary x:Key="Default">
<Color x:Key="HamburgerBaseHighColor">#99000000</Color>
<Color x:Key="HamburgerChromeMediumColor">#FFE6E6E6</Color>
<Color x:Key="HamburgerAltHighColor">#FFFFFFFF</Color>
<Color x:Key="HamburgerChromeLowColor">#FFF2F2F2</Color>
<SolidColorBrush x:Key="HomeCardBackground" Color="#FFFFFF" />
<SolidColorBrush x:Key="HomeCardBorderBrush" Color="#E5E5EA" />
<SolidColorBrush x:Key="HomeCardBorderBrushHover" Color="#3E6DF3" />
<SolidColorBrush x:Key="HomeSubtleForeground" Color="#64646E" />
<SolidColorBrush x:Key="HomeBadgeBackground" Color="#E8EFFD" />
<SolidColorBrush x:Key="HomeBadgeForeground" Color="#3462D9" />
</ResourceDictionary>
</ResourceDictionary.ThemeDictionaries>
<ControlTheme x:Key="ButtonCardTheme" TargetType="Button">
<Setter Property="HorizontalAlignment" Value="Stretch" />
<Setter Property="VerticalAlignment" Value="Stretch" />
<Setter Property="Background" Value="{DynamicResource HomeCardBackground}" />
<Setter Property="BorderBrush" Value="{DynamicResource HomeCardBorderBrush}" />
<Setter Property="BorderThickness" Value="1" />
<Setter Property="CornerRadius" Value="10" />
<Setter Property="Padding" Value="16, 14" />
<Setter Property="MinHeight" Value="118" />
<Setter Property="Cursor" Value="Hand" />
<Style Selector="^ /template/ ContentPresenter">
<Setter Property="BoxShadow" Value="0 1 3 0 #0D000000" />
<Setter Property="Transitions">
<Transitions>
<BrushTransition Property="BorderBrush" Duration="0:0:0.1" />
</Transitions>
</Setter>
</Style>
<Style Selector="^:pointerover /template/ ContentPresenter">
<Setter Property="BorderBrush" Value="{DynamicResource HomeCardBorderBrushHover}" />
</Style>
</ControlTheme>
<x:Double x:Key="NavigationItemHeight">36</x:Double>
<BoxShadows x:Key="NavigationItemShadow">1 1 1 1 #2000, 0 0 1 1 #2fff</BoxShadows>
<Thickness x:Key="NavigationItemPadding">8,0,4,0</Thickness>
<Thickness x:Key="NavigationItemSelectionPillMargin">2,0,0,0</Thickness>
<x:Double x:Key="SelectionPipeHeight">12</x:Double>
<ControlTheme x:Key="ScrollPage" TargetType="ContentPage">
<Setter Property="Background" Value="{DynamicResource PageBackgroundColor}"/>
<Setter Property="CornerRadius" Value="20,0,0,0"/>
<Setter Property="Template">
<ControlTemplate>
<Border
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Background="{TemplateBinding Background}"
CornerRadius="{TemplateBinding CornerRadius}">
<DockPanel>
<ContentPresenter Name="PART_TopCommandBar"
DockPanel.Dock="Top"
HorizontalContentAlignment="Stretch"
IsVisible="False" />
<ContentPresenter Name="PART_BottomCommandBar"
DockPanel.Dock="Bottom"
HorizontalContentAlignment="Stretch"
IsVisible="False" />
<ScrollViewer Padding="20"
HorizontalScrollBarVisibility="Disabled">
<ContentPresenter Name="PART_ContentPresenter"
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
Content="{TemplateBinding Content}"
ContentTemplate="{TemplateBinding ContentTemplate}"
CornerRadius="{TemplateBinding CornerRadius}" />
</ScrollViewer>
</DockPanel>
</Border>
</ControlTemplate>
</Setter>
</ControlTheme>
<ControlTheme x:Key="NavHeaderItem" TargetType="ListBoxItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
<Setter Property="VerticalContentAlignment" Value="Center" />
<Setter Property="HorizontalAlignment" Value="Stretch" />
<Setter Property="VerticalAlignment" Value="Stretch" />
<Setter Property="Background" Value="Transparent" />
<Setter Property="Height" Value="{StaticResource NavigationItemHeight}" />
<Setter Property="Padding" Value="{DynamicResource NavigationItemPadding}" />
<Setter Property="Margin" Value="4,2,8,0" />
<Setter Property="CornerRadius" Value="8" />
<Setter Property="ClipToBounds" Value="False" />
<Setter Property="Template">
<ControlTemplate>
<Border Name="PART_LayoutRoot"
HorizontalAlignment="{TemplateBinding HorizontalAlignment}"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="{TemplateBinding CornerRadius}">
<Panel>
<Border Name="PART_SelectedPipe"
Width="{DynamicResource TabItemPipeThickness}"
Height="{DynamicResource SelectionPipeHeight}"
Margin="{DynamicResource NavigationItemSelectionPillMargin}"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Background="{DynamicResource TabItemHeaderSelectedPipeFill}"
IsVisible="False"
CornerRadius="4"/>
<ContentPresenter Name="PART_ContentPresenter"
Padding="{TemplateBinding Padding}"
Margin="0"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
Content="{TemplateBinding Content}"
ContentTemplate="{TemplateBinding ContentTemplate}"
TextElement.FontFamily="{TemplateBinding FontFamily}"
TextElement.FontSize="{TemplateBinding FontSize}"
TextElement.FontWeight="{TemplateBinding FontWeight}" />
</Panel>
</Border>
</ControlTemplate>
</Setter>
<Style Selector="^:pointerover, ^:selected">
<Setter Property="Background" Value="{DynamicResource ThemeControlHighlightMidBrush}"/>
<Style Selector="^ /template/ Border#PART_LayoutRoot">
<Setter Property="Background" Value="{DynamicResource HamburgerChromeLowColor}" />
<Setter Property="BoxShadow" Value="{StaticResource NavigationItemShadow}" />
<Setter Property="TextElement.Foreground" Value="{DynamicResource HamburgerBaseHighColor}" />
</Style>
</Style>
<Style Selector="^:selected">
<Style Selector="^ /template/ Border#PART_SelectedPipe">
<Setter Property="IsVisible" Value="True" />
</Style>
</Style>
<Style Selector="^:pressed /template/ Border#PART_LayoutRoot">
<Setter Property="Border.Background" Value="{DynamicResource HamburgerChromeLowColor}" />
<Setter Property="Border.BoxShadow" Value="{StaticResource NavigationItemShadow}" />
<Setter Property="TextElement.Foreground" Value="{DynamicResource HamburgerBaseHighColor}" />
</Style>
</ControlTheme>
<ControlTheme x:Key="SelectableItemButton" TargetType="controls:SelectableButton">
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
<Setter Property="VerticalContentAlignment" Value="Center" />
<Setter Property="HorizontalAlignment" Value="Stretch" />
<Setter Property="VerticalAlignment" Value="Stretch" />
<Setter Property="Background" Value="Transparent" />
<Setter Property="Height" Value="{StaticResource NavigationItemHeight}" />
<Setter Property="Padding" Value="{DynamicResource NavigationItemPadding}" />
<Setter Property="CornerRadius" Value="8" />
<Setter Property="ClipToBounds" Value="False" />
<Setter Property="Template">
<ControlTemplate>
<Border Name="PART_LayoutRoot"
HorizontalAlignment="{TemplateBinding HorizontalAlignment}"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="{TemplateBinding CornerRadius}">
<Panel>
<Border Name="PART_SelectedPipe"
Width="{DynamicResource TabItemPipeThickness}"
Height="{DynamicResource SelectionPipeHeight}"
Margin="{DynamicResource NavigationItemSelectionPillMargin}"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Background="{DynamicResource TabItemHeaderSelectedPipeFill}"
IsVisible="False"
CornerRadius="4"/>
<ContentPresenter Name="PART_ContentPresenter"
Padding="{TemplateBinding Padding}"
Margin="0"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
Content="{TemplateBinding Content}"
ContentTemplate="{TemplateBinding ContentTemplate}"
TextElement.FontFamily="{TemplateBinding FontFamily}"
TextElement.FontSize="{TemplateBinding FontSize}"
TextElement.FontWeight="{TemplateBinding FontWeight}" />
</Panel>
</Border>
</ControlTemplate>
</Setter>
<Style Selector="^:pointerover, ^:selected">
<Setter Property="Background" Value="{DynamicResource ThemeControlHighlightMidBrush}"/>
<Style Selector="^ /template/ Border#PART_LayoutRoot">
<Setter Property="Background" Value="{DynamicResource HamburgerChromeLowColor}" />
<Setter Property="BoxShadow" Value="{StaticResource NavigationItemShadow}" />
</Style>
</Style>
<Style Selector="^:selected">
<Style Selector="^ /template/ Border#PART_SelectedPipe">
<Setter Property="IsVisible" Value="True" />
</Style>
</Style>
<Style Selector="^:pressed /template/ Border#PART_LayoutRoot">
<Setter Property="Border.Background" Value="{DynamicResource HamburgerChromeLowColor}" />
<Setter Property="Border.BoxShadow" Value="{StaticResource NavigationItemShadow}" />
<Setter Property="TextElement.Foreground" Value="{DynamicResource HamburgerBaseHighColor}" />
</Style>
</ControlTheme>
<ControlTheme x:Key="ExpanderToggleButton" TargetType="ToggleButton">
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
<Setter Property="VerticalContentAlignment" Value="Center" />
<Setter Property="HorizontalAlignment" Value="Stretch" />
<Setter Property="VerticalAlignment" Value="Stretch" />
<Setter Property="Background" Value="Transparent" />
<Setter Property="Height" Value="{StaticResource NavigationItemHeight}" />
<Setter Property="Padding" Value="{DynamicResource NavigationItemPadding}" />
<Setter Property="CornerRadius" Value="8" />
<Setter Property="ClipToBounds" Value="False" />
<Setter Property="Template">
<ControlTemplate>
<Border Name="PART_LayoutRoot"
HorizontalAlignment="{TemplateBinding HorizontalAlignment}"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="{TemplateBinding CornerRadius}">
<Panel>
<Border Name="PART_SelectedPipe"
Width="{DynamicResource TabItemPipeThickness}"
Height="{DynamicResource SelectionPipeHeight}"
Margin="{DynamicResource NavigationItemSelectionPillMargin}"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Background="{DynamicResource TabItemHeaderSelectedPipeFill}"
IsVisible="False"
CornerRadius="4"/>
<ContentPresenter Name="PART_ContentPresenter"
Padding="{TemplateBinding Padding}"
Margin="0"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
Content="{TemplateBinding Content}"
ContentTemplate="{TemplateBinding ContentTemplate}"
TextElement.FontFamily="{TemplateBinding FontFamily}"
TextElement.FontSize="{TemplateBinding FontSize}"
TextElement.FontWeight="{TemplateBinding FontWeight}" />
</Panel>
</Border>
</ControlTemplate>
</Setter>
<Style Selector="^:pointerover, ^:selected">
<Setter Property="Background" Value="{DynamicResource ThemeControlHighlightMidBrush}"/>
<Style Selector="^ /template/ Border#PART_LayoutRoot">
<Setter Property="Background" Value="{DynamicResource HamburgerChromeLowColor}" />
<Setter Property="BoxShadow" Value="{StaticResource NavigationItemShadow}" />
</Style>
</Style>
<Style Selector="^:checked">
<Style Selector="^ /template/ Border#PART_SelectedPipe">
<Setter Property="IsVisible" Value="True" />
</Style>
</Style>
<Style Selector="^:pressed /template/ Border#PART_LayoutRoot">
<Setter Property="Border.Background" Value="{DynamicResource HamburgerChromeLowColor}" />
<Setter Property="Border.BoxShadow" Value="{StaticResource NavigationItemShadow}" />
<Setter Property="TextElement.Foreground" Value="{DynamicResource HamburgerBaseHighColor}" />
</Style>
</ControlTheme>
<ControlTheme x:Key="HomeSectionExpander" TargetType="controls:HomeItemExpander">
<Setter Property="IsTabStop" Value="False"/>
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
<Setter Property="VerticalContentAlignment" Value="Center" />
<Setter Property="HorizontalAlignment" Value="Stretch" />
<Setter Property="VerticalAlignment" Value="Stretch" />
<Setter Property="Background" Value="Transparent" />
<Setter Property="MinHeight" Value="{StaticResource NavigationItemHeight}" />
<Setter Property="Padding" Value="{DynamicResource NavigationItemPadding}" />
<Setter Property="CornerRadius" Value="8" />
<Setter Property="ClipToBounds" Value="False" />
<Setter Property="Template">
<ControlTemplate>
<Border Name="PART_LayoutRoot"
HorizontalAlignment="{TemplateBinding HorizontalAlignment}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="{TemplateBinding CornerRadius}">
<Grid RowDefinitions="Auto,*">
<controls:SelectableButton x:Name="ExpanderHeader"
HorizontalAlignment="Stretch"
MinHeight="{TemplateBinding MinHeight}"
CornerRadius="{TemplateBinding CornerRadius}"
IsEnabled="{TemplateBinding IsEnabled}"
Content="{TemplateBinding Header}"
Command="{TemplateBinding Command}"
CommandParameter="{TemplateBinding CommandParameter}"
Theme="{StaticResource SelectableItemButton}"
Background="{TemplateBinding Background}"
IsSelected="{TemplateBinding IsSelected}"
IsChecked="{TemplateBinding IsExpanded, Mode=TwoWay}"
ContentTemplate="{TemplateBinding HeaderTemplate}" >
</controls:SelectableButton>
<Border x:Name="ExpanderContent"
Grid.Row="1"
IsVisible="{TemplateBinding IsEffectivelyExpanded, Mode=TwoWay}"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
MinHeight="{TemplateBinding MinHeight}"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Padding="{TemplateBinding Padding}">
<ContentPresenter x:Name="PART_ContentPresenter"
Content="{TemplateBinding Content}"
ContentTemplate="{TemplateBinding ContentTemplate}"
Foreground="{TemplateBinding Foreground}"
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}" />
</Border>
</Grid>
</Border>
</ControlTemplate>
</Setter>
<Style Selector="^:pointerover">
<Style Selector="^ /template/ controls|SelectableButton#ExpanderHeader">
<Setter Property="Background" Value="{DynamicResource HamburgerChromeLowColor}" />
</Style>
</Style>
<Style Selector="^:pressed /template/ Border#PART_LayoutRoot">
<Setter Property="Border.Background" Value="{DynamicResource HamburgerChromeLowColor}" />
<Setter Property="Border.BoxShadow" Value="{StaticResource NavigationItemShadow}" />
<Setter Property="TextElement.Foreground" Value="{DynamicResource HamburgerBaseHighColor}" />
</Style>
</ControlTheme>
</ResourceDictionary>

36
samples/ControlCatalog/Icons.cs

@ -193,5 +193,41 @@ namespace ControlCatalog
// Home
public const string Home = "M10,20V14H14V20H19V12H22L12,3L2,12H5V20H10Z";
// Desktop and Mobile
public const string DesktopMobile = "M8.255 9c.966 0 1.75.783 1.75 1.75v9.5A1.75 1.75 0 0 1 8.255 22H3.75A1.75 1.75 0 0 1 2 20.25v-9.5C2 9.783 2.784 9 3.75 9h4.505Zm0 1.5H3.75a.25.25 0 0 0-.25.25v9.5c0 .138.112.25.25.25h4.505a.25.25 0 0 0 .25-.25v-9.5a.25.25 0 0 0-.25-.25ZM6.25 18a.75.75 0 0 1 .102 1.493l-.102.007h-.5a.75.75 0 0 1-.102-1.493L5.75 18h.5Zm13.5-16a2.25 2.25 0 0 1 2.245 2.096L22 4.25v9a2.25 2.25 0 0 1-2.096 2.245l-.154.005h-3.746v2h1.246a.75.75 0 0 1 .102 1.493L17.25 19H11v-1.5h3.504v-2H11V14h8.75a.75.75 0 0 0 .743-.648l.007-.102v-9a.75.75 0 0 0-.75-.75H6.25a.75.75 0 0 0-.743.648L5.5 4.25V8H4V4.25a2.25 2.25 0 0 1 2.096-2.245L6.25 2h13.5Z";
// Keyboard float
public const string KeyboardFloat = "M21.25,19.5 C21.6642136,19.5 22,19.8357864 22,20.25 C22,20.6296958 21.7178461,20.943491 21.3517706,20.9931534 L21.25,21 L2.75,21 C2.33578644,21 2,20.6642136 2,20.25 C2,19.8703042 2.28215388,19.556509 2.64822944,19.5068466 L2.75,19.5 L21.25,19.5 Z M19.7453641,3 C20.9880048,3 21.9953641,4.00735931 21.9953641,5.25 L21.9953641,14.754591 C21.9953641,15.9972317 20.9880048,17.004591 19.7453641,17.004591 L13.2239763,17.0049687 C13.1062463,17.5730514 12.6029828,18 12,18 C11.3970172,18 10.8937537,17.5730514 10.7760237,17.0049687 L4.25,17.004591 C3.00735931,17.004591 2,15.9972317 2,14.754591 L2,5.25 C2,4.00735931 3.00735931,3 4.25,3 L19.7453641,3 Z M19.7453641,4.5 L4.25,4.5 C3.83578644,4.5 3.5,4.83578644 3.5,5.25 L3.5,14.754591 C3.5,15.1688046 3.83578644,15.504591 4.25,15.504591 L19.7453641,15.504591 C20.1595777,15.504591 20.4953641,15.1688046 20.4953641,14.754591 L20.4953641,5.25 C20.4953641,4.83578644 20.1595777,4.5 19.7453641,4.5 Z M17.25,12.5 C17.6642136,12.5 18,12.8357864 18,13.25 C18,13.6296958 17.7178461,13.943491 17.3517706,13.9931534 L17.25,14 L6.75,14 C6.33578644,14 6,13.6642136 6,13.25 C6,12.8703042 6.28215388,12.556509 6.64822944,12.5068466 L6.75,12.5 L17.25,12.5 Z M16.5,9 C17.0522847,9 17.5,9.44771525 17.5,10 C17.5,10.5522847 17.0522847,11 16.5,11 C15.9477153,11 15.5,10.5522847 15.5,10 C15.5,9.44771525 15.9477153,9 16.5,9 Z M10.5048752,9 C11.05716,9 11.5048752,9.44771525 11.5048752,10 C11.5048752,10.5522847 11.05716,11 10.5048752,11 C9.95259045,11 9.5048752,10.5522847 9.5048752,10 C9.5048752,9.44771525 9.95259045,9 10.5048752,9 Z M7.5048752,9 C8.05715995,9 8.5048752,9.44771525 8.5048752,10 C8.5048752,10.5522847 8.05715995,11 7.5048752,11 C6.95259045,11 6.5048752,10.5522847 6.5048752,10 C6.5048752,9.44771525 6.95259045,9 7.5048752,9 Z M13.5048752,9 C14.05716,9 14.5048752,9.44771525 14.5048752,10 C14.5048752,10.5522847 14.05716,11 13.5048752,11 C12.9525905,11 12.5048752,10.5522847 12.5048752,10 C12.5048752,9.44771525 12.9525905,9 13.5048752,9 Z M6,6 C6.55228475,6 7,6.44771525 7,7 C7,7.55228475 6.55228475,8 6,8 C5.44771525,8 5,7.55228475 5,7 C5,6.44771525 5.44771525,6 6,6 Z M8.9951248,6 C9.54740955,6 9.9951248,6.44771525 9.9951248,7 C9.9951248,7.55228475 9.54740955,8 8.9951248,8 C8.44284005,8 7.9951248,7.55228475 7.9951248,7 C7.9951248,6.44771525 8.44284005,6 8.9951248,6 Z M11.9951248,6 C12.5474095,6 12.9951248,6.44771525 12.9951248,7 C12.9951248,7.55228475 12.5474095,8 11.9951248,8 C11.44284,8 10.9951248,7.55228475 10.9951248,7 C10.9951248,6.44771525 11.44284,6 11.9951248,6 Z M14.9951248,6 C15.5474095,6 15.9951248,6.44771525 15.9951248,7 C15.9951248,7.55228475 15.5474095,8 14.9951248,8 C14.44284,8 13.9951248,7.55228475 13.9951248,7 C13.9951248,6.44771525 14.44284,6 14.9951248,6 Z M17.9951248,6 C18.5474095,6 18.9951248,6.44771525 18.9951248,7 C18.9951248,7.55228475 18.5474095,8 17.9951248,8 C17.44284,8 16.9951248,7.55228475 16.9951248,7 C16.9951248,6.44771525 17.44284,6 17.9951248,6 Z";
// Chats
public const string Chat = "M14.0038862,2.5 C20.3551608,2.5 25.5038862,7.64872538 25.5038862,14 C25.5038862,20.3512746 20.3551608,25.5 14.0038862,25.5 C12.0828262,25.5 10.2289934,25.0277557 8.57453454,24.1400553 L4.06949813,25.4927799 C3.40830889,25.6913248 2.71135661,25.3162775 2.51281166,24.6550883 C2.44236748,24.4204969 2.44239769,24.1703786 2.5128929,23.935823 L3.86597493,19.4333464 C2.97690068,17.777898 2.50388618,15.9226229 2.50388618,14 C2.50388618,7.64872538 7.65261155,2.5 14.0038862,2.5 Z M14.0038862,4 C8.48103868,4 4.00388618,8.4771525 4.00388618,14 C4.00388618,15.7703119 4.46384891,17.4718347 5.32571954,18.9725127 L5.48656853,19.2525809 L4.08316234,23.9225148 L8.75512584,22.5196672 L9.03501121,22.6802549 C10.5348218,23.5407899 12.2350195,24 14.0038862,24 C19.5267337,24 24.0038862,19.5228475 24.0038862,14 C24.0038862,8.4771525 19.5267337,4 14.0038862,4 Z M10.2538862,15.5 L14.7521489,15.5 C15.1663625,15.5 15.5021489,15.8357864 15.5021489,16.25 C15.5021489,16.6296958 15.219995,16.943491 14.8539195,16.9931534 L14.7521489,17 L10.2538862,17 C9.83967261,17 9.50388618,16.6642136 9.50388618,16.25 C9.50388618,15.8703042 9.78604006,15.556509 10.1521156,15.5068466 L10.2538862,15.5 L14.7521489,15.5 L10.2538862,15.5 Z M10.2538862,11 L17.7583662,11 C18.1725798,11 18.5083662,11.3357864 18.5083662,11.75 C18.5083662,12.1296958 18.2262123,12.443491 17.8601368,12.4931534 L17.7583662,12.5 L10.2538862,12.5 C9.83967261,12.5 9.50388618,12.1642136 9.50388618,11.75 C9.50388618,11.3703042 9.78604006,11.056509 10.1521156,11.0068466 L10.2538862,11 L17.7583662,11 L10.2538862,11 Z";
// Media
public const string Media = "M16.25 7.75a1.25 1.25 0 1 1-2.5 0 1.25 1.25 0 0 1 2.5 0Zm.667 9.242a1.78 1.78 0 0 1-.167.008h-1a.75.75 0 0 0 0 1.5h1c.966 0 1.75.784 1.75 1.75V21a.75.75 0 0 0 1.5 0v-.75a3.244 3.244 0 0 0-1.173-2.5A3.244 3.244 0 0 0 20 15.25v-9A3.25 3.25 0 0 0 16.75 3h-9.5A3.25 3.25 0 0 0 4 6.25v9c0 1.005.456 1.904 1.173 2.5A3.243 3.243 0 0 0 4 20.25V21a.75.75 0 0 0 1.5 0v-.75c0-.966.784-1.75 1.75-1.75h1a.75.75 0 0 0 0-1.5h-1c-.057 0-.113-.003-.168-.008l4.394-4.284a.75.75 0 0 1 1.047 0l4.394 4.284ZM7.25 4.5h9.5c.966 0 1.75.784 1.75 1.75v9c0 .342-.098.66-.267.93l-4.663-4.546a2.25 2.25 0 0 0-3.14 0l-4.663 4.545a1.742 1.742 0 0 1-.267-.929v-9c0-.966.784-1.75 1.75-1.75Zm4 12.5a.75.75 0 0 0 0 1.5h1.5a.75.75 0 0 0 0-1.5h-1.5Z";
// Layouts
public const string Layouts = "M2 5.75A2.75 2.75 0 0 1 4.75 3h14.5A2.75 2.75 0 0 1 22 5.75v12.5A2.75 2.75 0 0 1 19.25 21H4.75A2.75 2.75 0 0 1 2 18.25V5.75ZM4.75 4.5c-.69 0-1.25.56-1.25 1.25v12.5c0 .69.56 1.25 1.25 1.25h14.5c.69 0 1.25-.56 1.25-1.25V5.75c0-.69-.56-1.25-1.25-1.25H4.75Z";
// Three line Nav
public const string HamburgerUnread = "M19.25 8.5a2.75 2.75 0 1 0 0-5.5 2.75 2.75 0 0 0 0 5.5ZM15.576 6.503a3.768 3.768 0 0 1-.002-1.5H2.752l-.102.007a.75.75 0 0 0 .102 1.493h12.824ZM21.253 18h-18.5l-.102.007a.75.75 0 0 0 .102 1.493h18.5l.102-.007A.75.75 0 0 0 21.253 18ZM2.753 11.503h18.5a.75.75 0 0 1 .102 1.493l-.102.007h-18.5a.75.75 0 0 1-.102-1.493l.102-.007Z";
// Menus
public const string Menus = "M18.75,3 C19.940825,3 20.9156417,3.92516222 20.994809,5.09595127 L21,5.25 L21,18.75 C21,19.940825 20.074801,20.9156417 18.9040441,20.994809 L18.75,21 L5.25,21 C4.05913667,21 3.08435514,20.074801 3.00519082,18.9040441 L3,18.75 L3,5.25 C3,4.05913667 3.92516222,3.08435514 5.09595127,3.00519082 L5.25,3 L18.75,3 Z M18.75,4.5 L5.25,4.5 C4.8703075,4.5 4.55650958,4.78215688 4.50684668,5.14823019 L4.5,5.25 L4.5,18.75 C4.5,19.1296833 4.78215688,19.4434889 5.14823019,19.4931531 L5.25,19.5 L18.75,19.5 C19.1296833,19.5 19.4434889,19.2178347 19.4931531,18.8517677 L19.5,18.75 L19.5,5.25 C19.5,4.8703075 19.2178347,4.55650958 18.8517677,4.50684668 L18.75,4.5 Z M7.75,14.75 C8.30228,14.75 8.75,15.1977 8.75,15.75 C8.75,16.3023 8.30228,16.75 7.75,16.75 C7.19772,16.75 6.75,16.3023 6.75,15.75 C6.75,15.1977 7.19772,14.75 7.75,14.75 Z M16.7499,15 C17.1642,15 17.4999,15.3358 17.4999,15.75 C17.4999,16.1296833 17.2178188,16.4434889 16.8516887,16.4931531 L16.7499,16.5 L11.2501,16.5 C10.8358,16.5 10.5001,16.1642 10.5001,15.75 C10.5001,15.3703167 10.7821813,15.0565111 11.1483113,15.0068469 L11.2501,15 L16.7499,15 Z M7.75,11 C8.30228,11 8.75,11.4477 8.75,12 C8.75,12.5523 8.30228,13 7.75,13 C7.19772,13 6.75,12.5523 6.75,12 C6.75,11.4477 7.19772,11 7.75,11 Z M16.7499,11.25 C17.1642,11.25 17.4999,11.5858 17.4999,12 C17.4999,12.4142 17.1642,12.75 16.7499,12.75 L11.2501,12.75 C10.8358,12.75 10.5001,12.4142 10.5001,12 C10.5001,11.5858 10.8358,11.25 11.2501,11.25 L16.7499,11.25 Z M7.75,7.25 C8.30228,7.25 8.75,7.69772 8.75,8.25 C8.75,8.80228 8.30228,9.25 7.75,9.25 C7.19772,9.25 6.75,8.80228 6.75,8.25 C6.75,7.69772 7.19772,7.25 7.75,7.25 Z M16.75,7.5 C17.1642,7.5 17.5,7.83579 17.5,8.25 C17.5,8.66421 17.1642,9 16.75,9 L11.25,9 C10.8358,9 10.5,8.66421 10.5,8.25 C10.5,7.83579 10.8358,7.5 11.25,7.5 L16.75,7.5 Z";
// Date
public const string Date = "M21.75,3 C23.5449254,3 25,4.45507456 25,6.25 L25,21.75 C25,23.5449254 23.5449254,25 21.75,25 L6.25,25 C4.45507456,25 3,23.5449254 3,21.75 L3,6.25 C3,4.45507456 4.45507456,3 6.25,3 L21.75,3 Z M23.5,9.503 L4.5,9.503 L4.5,21.75 C4.5,22.7164983 5.28350169,23.5 6.25,23.5 L21.75,23.5 C22.7164983,23.5 23.5,22.7164983 23.5,21.75 L23.5,9.503 Z M16.9941406,12.234375 C17.7949259,12.234375 18.4296852,12.4472635 18.8984375,12.8730469 C19.3671898,13.2988303 19.6015625,13.8749964 19.6015625,14.6015625 C19.6015625,15.0195333 19.4941417,15.3915999 19.2792969,15.7177734 C19.0644521,16.0439469 18.7714862,16.3007803 18.4003906,16.4882813 C18.8457054,16.6953135 19.1884754,16.9785138 19.4287109,17.3378906 C19.6689465,17.6972674 19.7890625,18.1035134 19.7890625,18.5566406 C19.7890625,19.3066444 19.5351588,19.901365 19.0273437,20.3408203 C18.5195287,20.7802756 17.8437542,21 17,21 C16.1523395,21 15.4736354,20.7792991 14.9638672,20.3378906 C14.454099,19.8964822 14.1992187,19.3027381 14.1992187,18.5566406 C14.1992187,18.0996071 14.3203113,17.6894549 14.5625,17.3261719 C14.8046887,16.9628888 15.1445291,16.6835947 15.5820312,16.4882813 C15.2148419,16.3007803 14.9248058,16.0439469 14.7119141,15.7177734 C14.4990224,15.3915999 14.3925781,15.0195333 14.3925781,14.6015625 C14.3925781,13.8749964 14.6269508,13.2988303 15.0957031,12.8730469 C15.5644555,12.4472635 16.1972616,12.234375 16.9941406,12.234375 Z M11.9636719,12.3222656 L11.9636719,20.8828125 L10.5457031,20.8828125 L10.5457031,14.0332031 L8.45390625,14.7480469 L8.45390625,13.546875 L11.7820312,12.3222656 L11.9636719,12.3222656 Z M16.9882813,17.0742188 C16.5742167,17.0742188 16.2431653,17.2031237 15.9951172,17.4609375 C15.7470691,17.7187513 15.6230469,18.0605447 15.6230469,18.4863281 C15.6230469,18.904299 15.745116,19.23828 15.9892578,19.4882812 C16.2333997,19.7382825 16.5703104,19.8632812 17,19.8632812 C17.4296896,19.8632812 17.7646472,19.7421887 18.0048828,19.5 C18.2451184,19.2578113 18.3652344,18.919924 18.3652344,18.4863281 C18.3652344,18.064451 18.2392591,17.7236341 17.9873047,17.4638672 C17.7353503,17.2041003 17.4023458,17.0742188 16.9882813,17.0742188 Z M16.9941406,13.3769531 C16.6308576,13.3769531 16.3437511,13.4912098 16.1328125,13.7197266 C15.9218739,13.9482433 15.8164062,14.2597637 15.8164062,14.6542969 C15.8164062,15.0449238 15.9228505,15.3554676 16.1357422,15.5859375 C16.3486339,15.8164074 16.6367169,15.9316406 17,15.9316406 C17.3632831,15.9316406 17.6513661,15.8164074 17.8642578,15.5859375 C18.0771495,15.3554676 18.1835938,15.0449238 18.1835938,14.6542969 C18.1835938,14.2832013 18.0761729,13.9775403 17.8613281,13.7373047 C17.6464833,13.4970691 17.3574237,13.3769531 16.9941406,13.3769531 Z M21.75,4.5 L6.25,4.5 C5.28350169,4.5 4.5,5.28350169 4.5,6.25 L4.5,8.003 L23.5,8.003 L23.5,6.25 C23.5,5.28350169 22.7164983,4.5 21.75,4.5 Z";
// Lists
public const string Lists = "M7.24924 16C7.93921 16 8.49853 16.5593 8.49853 17.2493C8.49853 17.9393 7.93921 18.4986 7.24924 18.4986C6.55928 18.4986 5.99995 17.9393 5.99995 17.2493C5.99995 16.5593 6.55928 16 7.24924 16ZM10.75 16.5H21.25C21.6642 16.5 22 16.8358 22 17.25C22 17.6297 21.7178 17.9435 21.3517 17.9932L21.25 18H10.75C10.3357 18 9.99995 17.6642 9.99995 17.25C9.99995 16.8703 10.2821 16.5565 10.6482 16.5068L10.75 16.5ZM3.24904 11C3.93901 11 4.49833 11.5593 4.49833 12.2493C4.49833 12.9393 3.93901 13.4986 3.24904 13.4986C2.55908 13.4986 1.99976 12.9393 1.99976 12.2493C1.99976 11.5593 2.55908 11 3.24904 11ZM6.74976 11.5H21.25C21.6642 11.5 22 11.8358 22 12.25C22 12.6297 21.7178 12.9435 21.3517 12.9932L21.25 13H6.74976C6.33554 13 5.99976 12.6642 5.99976 12.25C5.99976 11.8703 6.28191 11.5565 6.64799 11.5068L6.74976 11.5ZM3.24924 6C3.93921 6 4.49853 6.55933 4.49853 7.24929C4.49853 7.93925 3.93921 8.49858 3.24924 8.49858C2.55928 8.49858 1.99995 7.93925 1.99995 7.24929C1.99995 6.55933 2.55928 6 3.24924 6ZM6.74995 6.5H21.25C21.6642 6.5 22 6.83579 22 7.25C22 7.6297 21.7178 7.94349 21.3517 7.99315L21.25 8H6.74995C6.33574 8 5.99995 7.66421 5.99995 7.25C5.99995 6.8703 6.28211 6.55651 6.64818 6.50685L6.74995 6.5Z";
// Textbox
public const string TextBox = "M18.25 3C19.7688 3 21 4.23122 21 5.75V18.25C21 19.7688 19.7688 21 18.25 21H5.75C4.23122 21 3 19.7688 3 18.25V5.75C3 4.23122 4.23122 3 5.75 3H18.25ZM18.25 4.5H5.75C5.05964 4.5 4.5 5.05964 4.5 5.75V18.25C4.5 18.9404 5.05964 19.5 5.75 19.5H18.25C18.9404 19.5 19.5 18.9404 19.5 18.25V5.75C19.5 5.05964 18.9404 4.5 18.25 4.5ZM14.25 11.5H6.75L6.64823 11.5068C6.28215 11.5565 6 11.8703 6 12.25C6 12.6642 6.33579 13 6.75 13H14.25L14.3518 12.9932C14.7178 12.9435 15 12.6297 15 12.25C15 11.8358 14.6642 11.5 14.25 11.5ZM6.75 15.5H17.25C17.6642 15.5 18 15.8358 18 16.25C18 16.6297 17.7178 16.9435 17.3518 16.9932L17.25 17H6.75C6.33579 17 6 16.6642 6 16.25C6 15.8703 6.28215 15.5565 6.64823 15.5068L6.75 15.5ZM17.25 7.5H6.75L6.64823 7.50685C6.28215 7.55651 6 7.8703 6 8.25C6 8.66421 6.33579 9 6.75 9H17.25L17.3518 8.99315C17.7178 8.94349 18 8.6297 18 8.25C18 7.83579 17.6642 7.5 17.25 7.5Z";
// Cursor 2
public const string Cursor2 = "M5.5 3.48349C5.5 2.23523 6.93571 1.5331 7.92098 2.29951L21.4353 12.8119C22.5626 13.6887 21.9425 15.4958 20.5143 15.4958H13.6619C13.1574 15.4958 12.6806 15.7267 12.3676 16.1224L8.17661 21.4226C7.2945 22.5382 5.5 21.9145 5.5 20.4923L5.5 3.48349ZM20.5143 13.9958L7 3.48349L7 20.4923L11.191 15.192C11.7884 14.4365 12.6987 13.9958 13.6619 13.9958H20.5143Z";
// Settings
public const string Settings = "M14 9.50006C11.5147 9.50006 9.5 11.5148 9.5 14.0001C9.5 16.4853 11.5147 18.5001 14 18.5001C15.3488 18.5001 16.559 17.9066 17.3838 16.9666C18.0787 16.1746 18.5 15.1365 18.5 14.0001C18.5 13.5401 18.431 13.0963 18.3028 12.6784C17.7382 10.8381 16.0253 9.50006 14 9.50006ZM11 14.0001C11 12.3432 12.3431 11.0001 14 11.0001C15.6569 11.0001 17 12.3432 17 14.0001C17 15.6569 15.6569 17.0001 14 17.0001C12.3431 17.0001 11 15.6569 11 14.0001Z M21.7093 22.3948L19.9818 21.6364C19.4876 21.4197 18.9071 21.4515 18.44 21.7219C17.9729 21.9924 17.675 22.4693 17.6157 23.0066L17.408 24.8855C17.3651 25.273 17.084 25.5917 16.7055 25.682C14.9263 26.1061 13.0725 26.1061 11.2933 25.682C10.9148 25.5917 10.6336 25.273 10.5908 24.8855L10.3834 23.0093C10.3225 22.4731 10.0112 21.9976 9.54452 21.7281C9.07783 21.4586 8.51117 21.4269 8.01859 21.6424L6.29071 22.4009C5.93281 22.558 5.51493 22.4718 5.24806 22.1859C4.00474 20.8536 3.07924 19.2561 2.54122 17.5137C2.42533 17.1384 2.55922 16.7307 2.8749 16.4977L4.40219 15.3703C4.83721 15.0501 5.09414 14.5415 5.09414 14.0007C5.09414 13.4598 4.83721 12.9512 4.40162 12.6306L2.87529 11.5051C2.55914 11.272 2.42513 10.8638 2.54142 10.4882C3.08038 8.74734 4.00637 7.15163 5.24971 5.82114C5.51684 5.53528 5.93492 5.44941 6.29276 5.60691L8.01296 6.36404C8.50793 6.58168 9.07696 6.54881 9.54617 6.27415C10.0133 6.00264 10.3244 5.52527 10.3844 4.98794L10.5933 3.11017C10.637 2.71803 10.9245 2.39704 11.3089 2.31138C12.19 2.11504 13.0891 2.01071 14.0131 2.00006C14.9147 2.01047 15.8128 2.11485 16.6928 2.31149C17.077 2.39734 17.3643 2.71823 17.4079 3.11017L17.617 4.98937C17.7116 5.85221 18.4387 6.50572 19.3055 6.50663C19.5385 6.507 19.769 6.45838 19.9843 6.36294L21.7048 5.60568C22.0626 5.44818 22.4807 5.53405 22.7478 5.81991C23.9912 7.1504 24.9172 8.74611 25.4561 10.487C25.5723 10.8623 25.4386 11.2703 25.1228 11.5035L23.5978 12.6297C23.1628 12.95 22.9 13.4586 22.9 13.9994C22.9 14.5403 23.1628 15.0489 23.5988 15.3698L25.1251 16.4965C25.441 16.7296 25.5748 17.1376 25.4586 17.5131C24.9198 19.2536 23.9944 20.8492 22.7517 22.1799C22.4849 22.4657 22.0671 22.5518 21.7093 22.3948ZM16.263 22.1966C16.4982 21.4685 16.9889 20.8288 17.6884 20.4238C18.5702 19.9132 19.6536 19.8547 20.5841 20.2627L21.9281 20.8526C22.791 19.8538 23.4593 18.7013 23.8981 17.4552L22.7095 16.5778L22.7086 16.5771C21.898 15.98 21.4 15.0277 21.4 13.9994C21.4 12.9719 21.8974 12.0195 22.7073 11.4227L22.7085 11.4218L23.8957 10.545C23.4567 9.2988 22.7881 8.14636 21.9248 7.1477L20.5922 7.73425L20.5899 7.73527C20.1844 7.91463 19.7472 8.00722 19.3039 8.00663C17.6715 8.00453 16.3046 6.77431 16.1261 5.15465L16.1259 5.15291L15.9635 3.69304C15.3202 3.57328 14.6677 3.50872 14.013 3.50017C13.3389 3.50891 12.6821 3.57367 12.0377 3.69328L11.8751 5.15452C11.7625 6.16272 11.1793 7.05909 10.3019 7.56986C9.41937 8.0856 8.34453 8.14844 7.40869 7.73694L6.07273 7.14893C5.20949 8.14751 4.54092 9.29983 4.10196 10.5459L5.29181 11.4233C6.11115 12.0269 6.59414 12.9837 6.59414 14.0007C6.59414 15.0173 6.11142 15.9742 5.29237 16.5776L4.10161 17.4566C4.54002 18.7044 5.2085 19.8585 6.07205 20.8587L7.41742 20.2682C8.34745 19.8613 9.41573 19.9215 10.2947 20.4292C11.174 20.937 11.7593 21.832 11.8738 22.84L11.8744 22.8445L12.0362 24.3088C13.3326 24.5638 14.6662 24.5638 15.9626 24.3088L16.1247 22.8418C16.1491 22.6217 16.1955 22.4055 16.263 22.1966Z";
}
}

269
samples/ControlCatalog/MainView.xaml

@ -1,13 +1,16 @@
<DrawerPage x:Class="ControlCatalog.MainView"
xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:ControlCatalog"
xmlns:controls="using:ControlCatalog.Controls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="using:ControlCatalog"
xmlns:models="using:ControlCatalog.Models"
xmlns:viewModels="using:ControlCatalog.ViewModels"
d:DesignWidth="1200"
d:DesignHeight="720"
CornerRadius="20"
x:DataType="viewModels:MainWindowViewModel"
DrawerBackground="Transparent"
DrawerLayoutBehavior="Split"
IsOpen="{Binding IsDrawerOpened , Mode=TwoWay}"
DisplayMode="{Binding DisplayMode, Mode=TwoWay}"
@ -26,6 +29,15 @@
<ControlTheme x:Key="{x:Type local:MainView}"
TargetType="local:MainView"
BasedOn="{StaticResource {x:Type DrawerPage}}" />
<ResourceDictionary.ThemeDictionaries>
<ResourceDictionary x:Key="Dark">
<Color x:Key="PageBackgroundColor">#FF171717</Color>
</ResourceDictionary>
<ResourceDictionary x:Key="Default">
<Color x:Key="PageBackgroundColor">#FFF2F2F2</Color>
</ResourceDictionary>
</ResourceDictionary.ThemeDictionaries>
</ResourceDictionary>
</DrawerPage.Resources>
<DrawerPage.Styles>
@ -34,131 +46,204 @@
<Setter Property="MaxWidth" Value="400" />
<Setter Property="HorizontalAlignment" Value="Left" />
</Style>
<Style Selector="FlexPanel.navItemFlex">
<Setter Property="Direction" Value="Row"/>
<Setter Property="AlignItems" Value="Center"/>
<Setter Property="Wrap" Value="NoWrap"/>
</Style>
</DrawerPage.Styles>
<DrawerPage.DrawerTemplate>
<DataTemplate x:DataType="viewModels:MainWindowViewModel">
<ListBox ItemsSource="{Binding Pages}"
Padding="0,10,0,10"
Background="Transparent"
ItemContainerTheme="{StaticResource NavHeaderItem}"
SelectedIndex="{Binding SelectedPageIndex}">
<ListBox.ItemTemplate>
<DataTemplate x:DataType="models:PageItem">
<Grid ColumnDefinitions="20,*">
<PathIcon Grid.Column="0" Width="16" Height="16"
<ScrollViewer HorizontalScrollBarVisibility="Disabled"
VerticalScrollBarVisibility="Auto">
<Grid RowDefinitions="Auto,*" Margin="5,0">
<controls:SelectableButton Margin="1"
Command="{Binding HomeCommand}"
Theme="{StaticResource SelectableItemButton}">
<controls:SelectableButton.IsSelected>
<MultiBinding Converter="{x:Static ObjectConverters.AreAllEqual}">
<Binding Path="$parent[local:MainView].ViewModel.CurrentPageItem.Header"/>
<Binding Path="$parent[local:MainView].ViewModel.HomeItem.Header"/>
</MultiBinding>
</controls:SelectableButton.IsSelected>
<FlexPanel Classes="navItemFlex">
<PathIcon Width="16" Height="16"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Data="{Binding IconData}"/>
<TextBlock Grid.Column="1" Text="{Binding Header}"
Data="{Binding HomeItem.IconData}"/>
<TextBlock DockPanel.Dock="Right" Text="{Binding HomeItem.Header}"
VerticalAlignment="Center"
Flex.Grow="1"
Margin="12,0,0,0"
IsVisible="{Binding IsDrawerOpened}"
TextTrimming="CharacterEllipsis"/>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</FlexPanel>
</controls:SelectableButton>
<ItemsControl ItemsSource="{Binding HomeSections}"
Grid.Row="1">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate x:DataType="models:HomeSection">
<controls:HomeItemExpander Theme="{StaticResource HomeSectionExpander}" Margin="1"
IsVisible="{Binding IsSectionVisible}"
IsExpanded="{Binding $parent[local:MainView].ViewModel.ExpandAllSections, Mode=OneWay}"
Command="{Binding $parent[local:MainView].ViewModel.NavigateToPageCommand}"
CommandParameter="{Binding PageItem}"
CanExpand="{Binding $parent[local:MainView].ViewModel.IsDrawerOpened}">
<controls:HomeItemExpander.IsSelected>
<MultiBinding Mode="OneWay" Converter="{x:Static BoolConverters.Or}">
<MultiBinding Mode="OneWay" Converter="{x:Static ObjectConverters.AreAllEqual}">
<Binding Path="$parent[local:MainView].ViewModel.CurrentPageItem.Header"/>
<Binding Path="Title"/>
</MultiBinding>
<MultiBinding Mode="OneWay" Converter="{x:Static ObjectConverters.AreAllEqual}">
<Binding Path="$parent[local:MainView].ViewModel.OpenedSection"/>
<Binding Path="Title"/>
</MultiBinding>
</MultiBinding>
</controls:HomeItemExpander.IsSelected>
<controls:HomeItemExpander.Header>
<FlexPanel Classes="navItemFlex">
<PathIcon Width="16" Height="16"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Data="{Binding IconData}"/>
<TextBlock Text="{Binding Title}" Classes="itemLabel"
VerticalAlignment="Center"
Margin="12,0,0,0"
Flex.Grow="1"
IsVisible="{Binding $parent[local:MainView].ViewModel.IsDrawerOpened}"
TextTrimming="CharacterEllipsis"/>
</FlexPanel>
</controls:HomeItemExpander.Header>
<controls:HomeItemExpander.Content>
<ItemsControl ItemsSource="{Binding Items}" Margin="10,0,0,0">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate x:DataType="models:PageItem">
<controls:SelectableButton Margin="1,2"
IsVisible="{Binding IsVisible}"
Theme="{StaticResource SelectableItemButton}"
Command="{Binding $parent[local:MainView].ViewModel.NavigateToPageCommand}"
CommandParameter="{Binding}">
<controls:SelectableButton.IsSelected>
<MultiBinding Mode="OneWay" Converter="{x:Static ObjectConverters.AreAllEqual}">
<Binding Path="$parent[local:MainView].ViewModel.CurrentPageItem.Header"/>
<Binding Path="Header"/>
</MultiBinding>
</controls:SelectableButton.IsSelected>
<FlexPanel Classes="navItemFlex">
<PathIcon Width="16" Height="16"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Data="{Binding IconData}"/>
<TextBlock Text="{Binding Header}" Classes="itemLabel"
VerticalAlignment="Center"
Margin="12,0,0,0"
Flex.Grow="1"
IsVisible="{Binding $parent[local:MainView].ViewModel.IsDrawerOpened}"
TextTrimming="CharacterEllipsis"/>
</FlexPanel>
</controls:SelectableButton>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</controls:HomeItemExpander.Content>
</controls:HomeItemExpander>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
</ScrollViewer>
</DataTemplate>
</DrawerPage.DrawerTemplate>
<DrawerPage.DrawerHeaderTemplate>
<DataTemplate x:DataType="viewModels:MainWindowViewModel">
<DockPanel LastChildFill="True" Margin="6">
<DockPanel.Styles>
<Style Selector="PathIcon#Icon">
<Setter Property="Width">32</Setter>
<Setter Property="Height">32</Setter>
</Style>
<ContainerQuery Name="IconHost" Query="min-width:60">
<Style Selector="PathIcon#Icon">
<Setter Property="Width">50</Setter>
<Setter Property="Height">50</Setter>
</Style>
</ContainerQuery>
<ContainerQuery Name="IconHost" Query="min-width:120">
<Style Selector="PathIcon#Icon">
<Setter Property="Width">100</Setter>
<Setter Property="Height">100</Setter>
</Style>
</ContainerQuery>
</DockPanel.Styles>
<TextBox Name="SearchBox"
DockPanel.Dock="Bottom"
PlaceholderText="Search..."
Text="{Binding Query, Mode=TwoWay}"
Margin="4,0,8,4"
VerticalContentAlignment="Center"
IsVisible="{Binding IsDrawerOpened}">
IsVisible="{Binding IsDrawerOpened}"
VerticalContentAlignment="Center">
<TextBox.InnerLeftContent>
<PathIcon Width="14" Height="14" Margin="6,0,0,0"
VerticalAlignment="Center"
Data="M10 2.5a7.5 7.5 0 0 1 5.964 12.048l4.743 4.745a1 1 0 0 1-1.32 1.497l-.094-.083-4.745-4.743A7.5 7.5 0 1 1 10 2.5Zm0 2a5.5 5.5 0 1 0 0 11 5.5 5.5 0 0 0 0-11Z" />
Data="{StaticResource SearchIcon}" />
</TextBox.InnerLeftContent>
</TextBox>
<Border HorizontalAlignment="Center" Padding="20"
<Border HorizontalAlignment="Center" Margin="0,10"
Background="Transparent"
Cursor="Hand"
Container.Name="IconHost"
Container.Sizing="Width"
Tapped="AvaloniaIcon_OnTapped">
<PathIcon VerticalAlignment="Center"
HorizontalAlignment="Center"
Height="100"
Width="100"
<PathIcon VerticalAlignment="Stretch"
HorizontalAlignment="Stretch"
Foreground="#007DF9"
Data="M24 0C37.2548 0 48 10.7452 48 24V42C48 45.3137 45.3137 48 42 48H24C10.7452 48 0 37.2548 0 24C0 10.7452 10.7452 0 24 0ZM24 7C16.3489 7 9.87832 12.0545 7.74496 19.0065C10.3931 19.1342 12.5 21.321 12.5 24C12.5 26.6793 10.3926 28.8664 7.74496 28.9941C9.83517 35.8054 16.0901 40.7958 23.5395 40.9939C26.6226 40.9252 29.1092 40.2605 31 39V41H41V24C41 14.827 33.7348 7.35088 24.6446 7.012L24.323 7.00301L24 7ZM24 16C28.4183 16 32 19.5817 32 24C32 28.4183 28.4183 32 24 32C19.5817 32 16 28.4183 16 24C16 19.5817 19.5817 16 24 16ZM7.5 20.5C5.567 20.5 4 22.067 4 24C4 25.933 5.567 27.5 7.5 27.5C9.433 27.5 11 25.933 11 24C11 22.067 9.433 20.5 7.5 20.5Z" />
Name="Icon"
Data="{StaticResource AppIcon}" />
</Border>
</DockPanel>
</DataTemplate>
</DrawerPage.DrawerHeaderTemplate>
<DrawerPage.DrawerFooterTemplate>
<DataTemplate x:DataType="viewModels:MainWindowViewModel">
<Expander HorizontalAlignment="Stretch"
HorizontalContentAlignment="Stretch"
Header="Settings"
Margin="0"
BorderThickness="0"
ExpandDirection="Up"
x:Name="SettingsExpander">
<StackPanel Width="152" Spacing="8">
<ComboBox x:Name="Decorations"
HorizontalAlignment="Stretch"
SelectedIndex="{Binding SelectedDecorationIndex}"
SelectionChanged="Decorations_SelectionChanged"
ToolTip.Tip="System Decorations">
<ComboBox.Items>
<WindowDecorations>None</WindowDecorations>
<WindowDecorations>BorderOnly</WindowDecorations>
<WindowDecorations>Full</WindowDecorations>
</ComboBox.Items>
</ComboBox>
<ComboBox HorizontalAlignment="Stretch"
DisplayMemberBinding="{Binding Key, x:DataType=ThemeVariant}"
SelectedIndex="0"
SelectionChanged="ThemeVariants_SelectionChanged"
ToolTip.Tip="Theme Variant">
<ComboBox.Items>
<ThemeVariant>Default</ThemeVariant>
<ThemeVariant>Light</ThemeVariant>
<ThemeVariant>Dark</ThemeVariant>
</ComboBox.Items>
</ComboBox>
<ComboBox HorizontalAlignment="Stretch"
SelectedItem="{x:Static local:App.CurrentTheme}"
SelectionChanged="Themes_SelectionChanged"
ToolTip.Tip="Catalog Theme">
<ComboBox.Items>
<models:CatalogTheme>Fluent</models:CatalogTheme>
<models:CatalogTheme>Simple</models:CatalogTheme>
</ComboBox.Items>
</ComboBox>
<ComboBox HorizontalAlignment="Stretch"
SelectedIndex="0"
SelectionChanged="TransparencyLevels_SelectionChanged"
ToolTip.Tip="Window Transparency Level">
<ComboBox.Items>
<WindowTransparencyLevel>None</WindowTransparencyLevel>
<WindowTransparencyLevel>Transparent</WindowTransparencyLevel>
<WindowTransparencyLevel>Blur</WindowTransparencyLevel>
<WindowTransparencyLevel>AcrylicBlur</WindowTransparencyLevel>
<WindowTransparencyLevel>Mica</WindowTransparencyLevel>
</ComboBox.Items>
</ComboBox>
<ComboBox HorizontalAlignment="Stretch"
SelectedIndex="0"
SelectionChanged="FlowDirection_SelectionChanged"
ToolTip.Tip="Flow Direction">
<ComboBox.Items>
<FlowDirection>LeftToRight</FlowDirection>
<FlowDirection>RightToLeft</FlowDirection>
</ComboBox.Items>
</ComboBox>
<ComboBox HorizontalAlignment="Stretch"
ItemsSource="{Binding WindowStates}"
SelectedItem="{Binding WindowState}"
ToolTip.Tip="Window State"/>
</StackPanel>
</Expander>
<controls:SelectableButton Margin="10"
Command="{Binding SettingsCommand}"
Theme="{StaticResource SelectableItemButton}">
<controls:SelectableButton.IsSelected>
<MultiBinding Converter="{x:Static ObjectConverters.AreAllEqual}">
<Binding Path="$parent[local:MainView].ViewModel.CurrentPageItem.Header"/>
<Binding Path="$parent[local:MainView].ViewModel.SettingsItem.Header"/>
</MultiBinding>
</controls:SelectableButton.IsSelected>
<FlexPanel Classes="navItemFlex">
<PathIcon Width="16" Height="16"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Data="{Binding SettingsItem.IconData}"/>
<TextBlock Text="{Binding SettingsItem.Header}" Classes="itemLabel"
VerticalAlignment="Center"
Margin="12,0,0,0"
Flex.Grow="1"
IsVisible="{Binding IsDrawerOpened}"
TextTrimming="CharacterEllipsis"/>
</FlexPanel>
</controls:SelectableButton>
</DataTemplate>
</DrawerPage.DrawerFooterTemplate>
<NavigationPage Name="NavPage"/>
<NavigationPage Name="NavPage">
<NavigationPage.Resources>
<SolidColorBrush x:Key="NavigationBarBackground">Transparent</SolidColorBrush>
</NavigationPage.Resources>
</NavigationPage>
</DrawerPage>

69
samples/ControlCatalog/MainView.xaml.cs

@ -3,18 +3,13 @@ using System.Threading.Tasks;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Input;
using Avalonia.Media;
using Avalonia.Media.Immutable;
using Avalonia.Styling;
using ControlCatalog.Models;
using ControlCatalog.ViewModels;
namespace ControlCatalog
{
public partial class MainView : DrawerPage
{
private readonly TransparentStyles _transparentStyles = new();
public MainView()
{
InitializeComponent();
@ -35,6 +30,11 @@ namespace ControlCatalog
SizeChanged += OnDrawerSizeChanged;
UpdateAdaptiveLayout();
if (Application.Current is { } app)
{
app.RequestedThemeVariant = ThemeVariant.Default;
}
}
private void MainView_Unloaded(object? sender, Avalonia.Interactivity.RoutedEventArgs e)
@ -89,59 +89,6 @@ namespace ControlCatalog
}
}
private void Themes_SelectionChanged(object? sender, SelectionChangedEventArgs e)
{
if (e.AddedItems.Count > 0 && e.AddedItems[0] is CatalogTheme theme)
{
App.SetCatalogThemes(theme);
}
}
private void ThemeVariants_SelectionChanged(object? sender, SelectionChangedEventArgs e)
{
if (Application.Current is { } app && e.AddedItems.Count > 0 && e.AddedItems[0] is ThemeVariant themeVariant)
{
app.RequestedThemeVariant = themeVariant;
}
}
private void FlowDirection_SelectionChanged(object? sender, SelectionChangedEventArgs e)
{
if (TopLevel.GetTopLevel(this) is { } topLevel && e.AddedItems.Count > 0 && e.AddedItems[0] is FlowDirection flowDirection)
{
topLevel.FlowDirection = flowDirection;
}
}
private void Decorations_SelectionChanged(object? sender, SelectionChangedEventArgs e)
{
if (TopLevel.GetTopLevel(this) is Window window && e.AddedItems.Count > 0 && e.AddedItems[0] is WindowDecorations systemDecorations)
{
window.WindowDecorations = systemDecorations;
}
}
private void TransparencyLevels_SelectionChanged(object? sender, SelectionChangedEventArgs e)
{
if (TopLevel.GetTopLevel(this) is { } topLevel && e.AddedItems.Count > 0 && e.AddedItems[0] is WindowTransparencyLevel transparencyLevel)
{
topLevel.TransparencyLevelHint = [transparencyLevel];
if (topLevel.ActualTransparencyLevel != WindowTransparencyLevel.None &&
transparencyLevel != WindowTransparencyLevel.None)
{
topLevel.Background = new ImmutableSolidColorBrush(Colors.Gray, 0.2);
if (!topLevel.Styles.Contains(_transparentStyles))
topLevel.Styles.Add(_transparentStyles);
}
else
{
topLevel.Background = null;
topLevel.Styles.Remove(_transparentStyles);
}
}
}
protected override void OnDataContextChanged(EventArgs e)
{
base.OnDataContextChanged(e);
@ -149,6 +96,8 @@ namespace ControlCatalog
if (ViewModel != null)
{
ViewModel.Navigator = NavPage;
ViewModel.NavigateToItem(ViewModel.HomeItem);
}
}
@ -164,8 +113,6 @@ namespace ControlCatalog
UpdateAdaptiveLayout();
var topLevel = TopLevel.GetTopLevel(this)!;
if (topLevel is Window window)
ViewModel.SelectedDecorationIndex = (int)window.WindowDecorations;
var insets = topLevel.InsetsManager;
if (insets != null)
@ -197,8 +144,6 @@ namespace ControlCatalog
ViewModel.IsSystemBarVisible = insets.IsSystemBarVisible ?? true;
};
}
ViewModel.SelectedPageIndex = 0;
}
private async void AvaloniaIcon_OnTapped(object? sender, TappedEventArgs e)

18
samples/ControlCatalog/MainWindow.xaml

@ -12,7 +12,8 @@
CanMaximize="{Binding CanMaximize}"
WindowDrawnDecorations.TitleBarDecorations="{Binding TitleBarDecorations}"
Win32Properties.WindowCornerPreference="{Binding Win32WindowCornerPreference}"
x:Class="ControlCatalog.MainWindow" WindowState="{Binding WindowState, Mode=TwoWay}"
x:Class="ControlCatalog.MainWindow"
WindowState="{Binding SettingsViewModel.WindowState, Mode=TwoWay}"
x:DataType="vm:MainWindowViewModel">
<NativeMenu.Menu>
<NativeMenu>
@ -59,20 +60,5 @@
<Panel Margin="{Binding $parent[local:MainWindow].OffScreenMargin}">
<local:MainView Margin="{Binding $parent[local:MainWindow].WindowDecorationMargin}" />
</Panel>
<Border IsVisible="{Binding ExtendClientAreaEnabled}"
BorderThickness="1"
CornerRadius="4"
BorderBrush="#55000000"
VerticalAlignment="Top"
HorizontalAlignment="Left"
Margin="250,0,0,0"
Height="{Binding $parent[local:MainWindow].WindowDecorationMargin.Top}">
<Border.Background>
<SolidColorBrush Color="DodgerBlue" Opacity="0.7" />
</Border.Background>
<TextBlock Text="Content In Title Bar"
Margin="4"
VerticalAlignment="Center" />
</Border>
</Panel>
</Window>

28
samples/ControlCatalog/Models/HomeSection.cs

@ -1,10 +1,30 @@
using System.Collections.Generic;
using ControlCatalog.ViewModels;
using System.Linq;
using Avalonia.Media;
using ControlCatalog.Pages;
using MiniMvvm;
namespace ControlCatalog.Models;
public class HomeSection(string title, IReadOnlyList<PageItem> items)
public class HomeSection : ViewModelBase
{
public string Title { get; } = title;
public IReadOnlyList<PageItem> Items { get; } = items;
public string Title { get; }
public StreamGeometry IconData { get; }
public IReadOnlyList<PageItem>? Items { get; set; }
public bool IsSectionVisible => Items?.Any(x => x.IsVisible) == true;
public PageItem PageItem { get; }
public HomeSection(string title, StreamGeometry iconData)
{
Title = title;
IconData = iconData;
PageItem = new PageItem(title, () => new SectionPage(this), iconData, "", null);
}
public void RaiseSectionVisibilityChanged()
{
RaisePropertyChanged(nameof(IsSectionVisible));
}
}

16
samples/ControlCatalog/Models/PageItem.cs

@ -3,17 +3,27 @@ using System.Globalization;
using System.Text;
using Avalonia.Controls;
using Avalonia.Media;
using MiniMvvm;
namespace ControlCatalog.Models;
public class PageItem(string header, Func<Page> factory, StreamGeometry iconData, string description, string section)
public class PageItem(string header, Func<Page> factory, StreamGeometry iconData, string description, HomeSection? section) : ViewModelBase
{
public string Header { get; } = header;
public StreamGeometry? IconData { get; } = iconData;
public string? Description { get; } = description;
private string SearchKey { get; } = CreateSearchKey(header, section);
public string Section { get; } = section?.Title ?? "";
private string SearchKey { get; } = CreateSearchKey(header, section?.Title ?? "");
public bool IsVisible { get; set; } = true;
public bool IsVisible
{
get;
set
{
RaiseAndSetIfChanged(ref field, value);
section?.RaiseSectionVisibilityChanged();
}
} = true;
public Page CreatePage() => factory();

101
samples/ControlCatalog/NavHeaderItem.xaml

@ -1,101 +0,0 @@
<ResourceDictionary xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="using:ControlCatalog">
<ResourceDictionary.ThemeDictionaries>
<ResourceDictionary x:Key="Dark">
<Color x:Key="HamburgerBaseHighColor">#99FFFFFF</Color>
<Color x:Key="HamburgerChromeMediumColor">#FF1F1F1F</Color>
<Color x:Key="HamburgerAltHighColor">#FF000000</Color>
<Color x:Key="HamburgerChromeLowColor">#FF171717</Color>
</ResourceDictionary>
<ResourceDictionary x:Key="Default">
<Color x:Key="HamburgerBaseHighColor">#99000000</Color>
<Color x:Key="HamburgerChromeMediumColor">#FFE6E6E6</Color>
<Color x:Key="HamburgerAltHighColor">#FFFFFFFF</Color>
<Color x:Key="HamburgerChromeLowColor">#FFF2F2F2</Color>
</ResourceDictionary>
</ResourceDictionary.ThemeDictionaries>
<x:Double x:Key="NavigationItemHeight">36</x:Double>
<BoxShadows x:Key="NavigationItemShadow">1 1 1 1 #2000, 0 0 1 1 #2fff</BoxShadows>
<Design.PreviewWith>
<Border Padding="0">
<ListBox ItemContainerTheme="{StaticResource NavHeaderItem}">
<ListBoxItem IsEnabled="False">Disabled</ListBoxItem>
<ListBoxItem>
Test
</ListBoxItem>
<ListBoxItem>Test</ListBoxItem>
</ListBox>
</Border>
</Design.PreviewWith>
<ControlTheme x:Key="NavHeaderItem" TargetType="ListBoxItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
<Setter Property="VerticalContentAlignment" Value="Center" />
<Setter Property="HorizontalAlignment" Value="Stretch" />
<Setter Property="VerticalAlignment" Value="Stretch" />
<Setter Property="Background" Value="Transparent" />
<Setter Property="Height" Value="{StaticResource NavigationItemHeight}" />
<Setter Property="Padding" Value="14,0,4,0" />
<Setter Property="Margin" Value="4,2,8,0" />
<Setter Property="CornerRadius" Value="8" />
<Setter Property="ClipToBounds" Value="False" />
<Setter Property="Template">
<ControlTemplate>
<Border Name="PART_LayoutRoot"
HorizontalAlignment="{TemplateBinding HorizontalAlignment}"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="{TemplateBinding CornerRadius}">
<Panel>
<Border Name="PART_SelectedPipe"
Width="{DynamicResource TabItemPipeThickness}"
Height="{DynamicResource TabItemVerticalPipeHeight}"
Margin="6,0,0,0"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Background="{DynamicResource TabItemHeaderSelectedPipeFill}"
IsVisible="False"
CornerRadius="4"/>
<ContentPresenter Name="PART_ContentPresenter"
Padding="{TemplateBinding Padding}"
Margin="0"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
Content="{TemplateBinding Content}"
ContentTemplate="{TemplateBinding ContentTemplate}"
TextElement.FontFamily="{TemplateBinding FontFamily}"
TextElement.FontSize="{TemplateBinding FontSize}"
TextElement.FontWeight="{TemplateBinding FontWeight}" />
</Panel>
</Border>
</ControlTemplate>
</Setter>
<Style Selector="^:pointerover">
<Setter Property="Background" Value="{DynamicResource ThemeControlHighlightMidBrush}"/>
<Style Selector="^ /template/ Border#PART_LayoutRoot">
<Setter Property="Background" Value="{DynamicResource HamburgerChromeLowColor}" />
<Setter Property="BoxShadow" Value="{StaticResource NavigationItemShadow}" />
<Setter Property="TextElement.Foreground" Value="{DynamicResource HamburgerBaseHighColor}" />
</Style>
</Style>
<Style Selector="^:selected">
<Setter Property="Background" Value="{DynamicResource ThemeAccentBrush4}"/>
<Style Selector="^ /template/ Border#PART_SelectedPipe">
<Setter Property="IsVisible" Value="True" />
</Style>
</Style>
<Style Selector="^:pressed /template/ Border#PART_LayoutRoot">
<Setter Property="Border.Background" Value="{DynamicResource HamburgerChromeLowColor}" />
<Setter Property="Border.BoxShadow" Value="{StaticResource NavigationItemShadow}" />
<Setter Property="TextElement.Foreground" Value="{DynamicResource HamburgerBaseHighColor}" />
</Style>
</ControlTheme>
</ResourceDictionary>

92
samples/ControlCatalog/Pages/HomePage.xaml

@ -4,58 +4,10 @@
xmlns:viewModels="using:ControlCatalog.ViewModels"
xmlns:controlCatalog="using:ControlCatalog"
xmlns:models="clr-namespace:ControlCatalog.Models"
xmlns:controls="using:ControlCatalog.Controls"
x:Class="ControlCatalog.Pages.HomePage"
Header="Home">
<ContentPage.Resources>
<ResourceDictionary>
<ResourceDictionary.ThemeDictionaries>
<ResourceDictionary x:Key="Default">
<SolidColorBrush x:Key="HomeCardBackground" Color="#FFFFFF" />
<SolidColorBrush x:Key="HomeCardBorderBrush" Color="#E5E5EA" />
<SolidColorBrush x:Key="HomeCardBorderBrushHover" Color="#3E6DF3" />
<SolidColorBrush x:Key="HomeSubtleForeground" Color="#64646E" />
<SolidColorBrush x:Key="HomeBadgeBackground" Color="#E8EFFD" />
<SolidColorBrush x:Key="HomeBadgeForeground" Color="#3462D9" />
</ResourceDictionary>
<ResourceDictionary x:Key="Dark">
<SolidColorBrush x:Key="HomeCardBackground" Color="#2B2B33" />
<SolidColorBrush x:Key="HomeCardBorderBrush" Color="#3A3A45" />
<SolidColorBrush x:Key="HomeCardBorderBrushHover" Color="#8AB4FF" />
<SolidColorBrush x:Key="HomeSubtleForeground" Color="#9C9CAB" />
<SolidColorBrush x:Key="HomeBadgeBackground" Color="#31395A" />
<SolidColorBrush x:Key="HomeBadgeForeground" Color="#8AB4FF" />
</ResourceDictionary>
</ResourceDictionary.ThemeDictionaries>
<ControlTheme x:Key="ButtonCardTheme" TargetType="Button">
<Setter Property="HorizontalAlignment" Value="Stretch" />
<Setter Property="VerticalAlignment" Value="Stretch" />
<Setter Property="Background" Value="{DynamicResource HomeCardBackground}" />
<Setter Property="BorderBrush" Value="{DynamicResource HomeCardBorderBrush}" />
<Setter Property="BorderThickness" Value="1" />
<Setter Property="CornerRadius" Value="10" />
<Setter Property="Padding" Value="16, 14" />
<Setter Property="MinHeight" Value="118" />
<Setter Property="Cursor" Value="Hand" />
<Style Selector="^ /template/ ContentPresenter">
<Setter Property="BoxShadow" Value="0 1 3 0 #0D000000" />
<Setter Property="Transitions">
<Transitions>
<BrushTransition Property="BorderBrush" Duration="0:0:0.1" />
</Transitions>
</Setter>
</Style>
<Style Selector="^:pointerover /template/ ContentPresenter">
<Setter Property="BorderBrush" Value="{DynamicResource HomeCardBorderBrushHover}" />
</Style>
</ControlTheme>
</ResourceDictionary>
</ContentPage.Resources>
<StackPanel Spacing="28" Margin="0,0,15,20" HorizontalAlignment="Stretch"
DataContext="{Binding $parent[controlCatalog:MainView].((viewModels:MainWindowViewModel)DataContext)}">
@ -101,48 +53,10 @@
<ItemsControl ItemsSource="{Binding HomeSections}">
<ItemsControl.ItemTemplate>
<DataTemplate DataType="models:HomeSection">
<StackPanel Spacing="14" Margin="0,0,0,26">
<StackPanel Spacing="14">
<TextBlock Text="{Binding Title}"
FontSize="19" FontWeight="Bold" />
<ItemsControl ItemsSource="{Binding Items}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid RowSpacing="12" ColumnSpacing="12"
Margin="0, 0, 1, 0"
SizeChanged="UniformGrid_OnSizeChanged" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate DataType="models:PageItem">
<Button Theme="{StaticResource ButtonCardTheme}"
Command="{Binding $parent[controlCatalog:MainView].((viewModels:MainWindowViewModel)DataContext).NavigateToPageCommand}"
CommandParameter="{Binding}">
<StackPanel Spacing="10">
<Border Background="{DynamicResource HomeBadgeBackground}"
CornerRadius="8"
Width="36" Height="36"
HorizontalAlignment="Left">
<PathIcon Data="{Binding IconData}"
Foreground="{DynamicResource HomeBadgeForeground}"
Width="18" Height="18"
HorizontalAlignment="Center"
VerticalAlignment="Center" />
</Border>
<StackPanel Spacing="3">
<TextBlock Text="{Binding Header}"
FontSize="14" FontWeight="SemiBold" />
<TextBlock Text="{Binding Description}"
FontSize="12"
Foreground="{DynamicResource HomeSubtleForeground}"
TextWrapping="Wrap"
TextTrimming="CharacterEllipsis"
MaxLines="2" />
</StackPanel>
</StackPanel>
</Button>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<controls:SectionControl DataContext="{Binding}" />
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>

15
samples/ControlCatalog/Pages/SectionPage.axaml

@ -0,0 +1,15 @@
<ContentPage Theme="{StaticResource ScrollPage}"
xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="using:ControlCatalog.Controls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:viewModels="using:ControlCatalog.ViewModels"
mc:Ignorable="d"
d:DesignWidth="800"
d:DesignHeight="450"
Header="{Binding HomeSection.Title}"
x:DataType="viewModels:SectionViewModel"
x:Class="ControlCatalog.Pages.SectionPage">
<controls:SectionControl DataContext="{Binding HomeSection}" />
</ContentPage>

23
samples/ControlCatalog/Pages/SectionPage.axaml.cs

@ -0,0 +1,23 @@
using System;
using Avalonia.Controls;
using Avalonia.Controls.Primitives;
using ControlCatalog.Models;
using ControlCatalog.ViewModels;
namespace ControlCatalog.Pages
{
public partial class SectionPage : ContentPage
{
public SectionPage(HomeSection homeSection)
{
InitializeComponent();
DataContext = new SectionViewModel(homeSection);
}
public SectionPage()
{
InitializeComponent();
}
}
}

150
samples/ControlCatalog/Pages/SettingsPage.axaml

@ -0,0 +1,150 @@
<ContentPage Theme="{StaticResource ScrollPage}" 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"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
xmlns:local="using:ControlCatalog"
xmlns:models="using:ControlCatalog.Models"
Header="Settings"
Margin="20"
xmlns:viewModels="using:ControlCatalog.ViewModels"
x:DataType="viewModels:SettingsViewModel"
x:Class="ControlCatalog.Pages.SettingsPage">
<ContentPage.Resources>
<ResourceDictionary>
<ResourceDictionary.ThemeDictionaries>
<ResourceDictionary x:Key="Default">
<SolidColorBrush x:Key="CardBackground" Color="#FFFFFF" />
<SolidColorBrush x:Key="CardBorderBrush" Color="#E5E5EA" />
<SolidColorBrush x:Key="CardBorderBrushHover" Color="#3E6DF3" />
<SolidColorBrush x:Key="SubtleForeground" Color="#64646E" />
<SolidColorBrush x:Key="BadgeBackground" Color="#E8EFFD" />
<SolidColorBrush x:Key="BadgeForeground" Color="#3462D9" />
</ResourceDictionary>
<ResourceDictionary x:Key="Dark">
<SolidColorBrush x:Key="CardBackground" Color="#2B2B33" />
<SolidColorBrush x:Key="CardBorderBrush" Color="#3A3A45" />
<SolidColorBrush x:Key="CardBorderBrushHover" Color="#8AB4FF" />
<SolidColorBrush x:Key="SubtleForeground" Color="#9C9CAB" />
<SolidColorBrush x:Key="BadgeBackground" Color="#31395A" />
<SolidColorBrush x:Key="BadgeForeground" Color="#8AB4FF" />
</ResourceDictionary>
</ResourceDictionary.ThemeDictionaries>
</ResourceDictionary>
</ContentPage.Resources>
<ContentPage.Styles>
<Style Selector="ComboBox">
<Setter Property="MinWidth">200</Setter>
</Style>
<Style Selector="Border.card">
<Setter Property="Background" Value="{DynamicResource CardBackground}"/>
<Setter Property="BorderBrush" Value="{DynamicResource CardBorderBrush}" />
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="Padding" Value="10"/>
<Setter Property="CornerRadius" Value="10"/>
</Style>
<Style Selector="Border.card Label">
<Setter Property="VerticalAlignment" Value="Center"/>
</Style>
</ContentPage.Styles>
<StackPanel Orientation="Vertical" Spacing="10">
<Border Classes="card">
<Grid ColumnSpacing="10" ColumnDefinitions="*,Auto">
<Label>Window Decorations</Label>
<ComboBox x:Name="Decorations"
Grid.Column="1"
HorizontalAlignment="Stretch"
SelectedIndex="{Binding SelectedDecorationIndex}"
SelectionChanged="Decorations_SelectionChanged"
ToolTip.Tip="System Decorations">
<ComboBox.Items>
<WindowDecorations>None</WindowDecorations>
<WindowDecorations>BorderOnly</WindowDecorations>
<WindowDecorations>Full</WindowDecorations>
</ComboBox.Items>
</ComboBox>
</Grid>
</Border>
<Border Classes="card">
<Grid ColumnSpacing="10" ColumnDefinitions="*,Auto">
<Label>Theme</Label>
<ComboBox HorizontalAlignment="Stretch"
Grid.Column="1"
SelectedItem="{x:Static local:App.CurrentTheme}"
SelectionChanged="Themes_SelectionChanged"
ToolTip.Tip="Catalog Theme">
<ComboBox.Items>
<models:CatalogTheme>Fluent</models:CatalogTheme>
<models:CatalogTheme>Simple</models:CatalogTheme>
</ComboBox.Items>
</ComboBox>
</Grid>
</Border>
<Border Classes="card">
<Grid ColumnSpacing="10" ColumnDefinitions="*,Auto">
<Label>Theme Variant</Label>
<ComboBox HorizontalAlignment="Stretch"
Grid.Column="1"
DisplayMemberBinding="{Binding Key, x:DataType=ThemeVariant}"
SelectedIndex="{Binding SelectedThemeVariantIndex}"
SelectionChanged="ThemeVariants_SelectionChanged"
ToolTip.Tip="Theme Variant">
<ComboBox.Items>
<ThemeVariant>Default</ThemeVariant>
<ThemeVariant>Light</ThemeVariant>
<ThemeVariant>Dark</ThemeVariant>
</ComboBox.Items>
</ComboBox>
</Grid>
</Border>
<Border Classes="card">
<Grid ColumnSpacing="10" ColumnDefinitions="*,Auto">
<Label>Window Transparency</Label>
<ComboBox HorizontalAlignment="Stretch"
Grid.Column="1"
SelectedIndex="{Binding SelectedTransparencyLevelIndex}"
SelectionChanged="TransparencyLevels_SelectionChanged"
ToolTip.Tip="Window Transparency Level">
<ComboBox.Items>
<WindowTransparencyLevel>None</WindowTransparencyLevel>
<WindowTransparencyLevel>Transparent</WindowTransparencyLevel>
<WindowTransparencyLevel>Blur</WindowTransparencyLevel>
<WindowTransparencyLevel>AcrylicBlur</WindowTransparencyLevel>
<WindowTransparencyLevel>Mica</WindowTransparencyLevel>
</ComboBox.Items>
</ComboBox>
</Grid>
</Border>
<Border Classes="card">
<Grid ColumnSpacing="10" ColumnDefinitions="*,Auto">
<Label>Flow Direction</Label>
<ComboBox HorizontalAlignment="Stretch"
Grid.Column="1"
SelectedIndex="{Binding SelectedFlowDirectionIndex}"
SelectionChanged="FlowDirection_SelectionChanged"
ToolTip.Tip="Flow Direction">
<ComboBox.Items>
<FlowDirection>LeftToRight</FlowDirection>
<FlowDirection>RightToLeft</FlowDirection>
</ComboBox.Items>
</ComboBox>
</Grid>
</Border>
<Border Classes="card">
<Grid ColumnSpacing="10" ColumnDefinitions="*,Auto">
<Label>Window State</Label>
<ComboBox HorizontalAlignment="Stretch"
Grid.Column="1"
ItemsSource="{Binding WindowStates}"
SelectedItem="{Binding WindowState}"
ToolTip.Tip="Window State"/>
</Grid>
</Border>
</StackPanel>
</ContentPage>

93
samples/ControlCatalog/Pages/SettingsPage.axaml.cs

@ -0,0 +1,93 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Media;
using Avalonia.Media.Immutable;
using Avalonia.Styling;
using ControlCatalog.Models;
using ControlCatalog.ViewModels;
namespace ControlCatalog.Pages
{
public partial class SettingsPage : ContentPage
{
private readonly TransparentStyles _transparentStyles = new();
public SettingsPage(SettingsViewModel settingsViewModel)
{
InitializeComponent();
DataContext = settingsViewModel;
}
public SettingsPage()
{
InitializeComponent();
DataContext = new SettingsViewModel();
}
protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
{
base.OnAttachedToVisualTree(e);
if (DataContext is SettingsViewModel viewModel)
{
var topLevel = TopLevel.GetTopLevel(this)!;
if (topLevel is Window window)
viewModel.SelectedDecorationIndex = (int)window.WindowDecorations;
}
}
private void Decorations_SelectionChanged(object? sender, SelectionChangedEventArgs e)
{
if (TopLevel.GetTopLevel(this) is Window window && e.AddedItems.Count > 0 && e.AddedItems[0] is WindowDecorations systemDecorations)
{
window.WindowDecorations = systemDecorations;
}
}
private void Themes_SelectionChanged(object? sender, SelectionChangedEventArgs e)
{
if (e.AddedItems.Count > 0 && e.AddedItems[0] is CatalogTheme theme)
{
App.SetCatalogThemes(theme);
}
}
private void ThemeVariants_SelectionChanged(object? sender, SelectionChangedEventArgs e)
{
if (Application.Current is { } app && e.AddedItems.Count > 0 && e.AddedItems[0] is ThemeVariant themeVariant)
{
app.RequestedThemeVariant = themeVariant;
}
}
private void FlowDirection_SelectionChanged(object? sender, SelectionChangedEventArgs e)
{
if (TopLevel.GetTopLevel(this) is { } topLevel && e.AddedItems.Count > 0 && e.AddedItems[0] is FlowDirection flowDirection)
{
topLevel.FlowDirection = flowDirection;
}
}
private void TransparencyLevels_SelectionChanged(object? sender, SelectionChangedEventArgs e)
{
if (TopLevel.GetTopLevel(this) is { } topLevel && e.AddedItems.Count > 0 && e.AddedItems[0] is WindowTransparencyLevel transparencyLevel)
{
topLevel.TransparencyLevelHint = [transparencyLevel];
if (topLevel.ActualTransparencyLevel != WindowTransparencyLevel.None &&
transparencyLevel != WindowTransparencyLevel.None)
{
topLevel.Background = new ImmutableSolidColorBrush(Colors.Gray, 0.2);
if (!topLevel.Styles.Contains(_transparentStyles))
topLevel.Styles.Add(_transparentStyles);
}
else
{
topLevel.Background = null;
topLevel.Styles.Remove(_transparentStyles);
}
}
}
}
}

34
samples/ControlCatalog/ScrollPage.xaml

@ -1,34 +0,0 @@
<ResourceDictionary xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="using:ControlCatalog">
<ControlTheme x:Key="ScrollPage" TargetType="ContentPage">
<Setter Property="Template">
<ControlTemplate>
<DockPanel>
<ContentPresenter Name="PART_TopCommandBar"
DockPanel.Dock="Top"
HorizontalContentAlignment="Stretch"
IsVisible="False" />
<ContentPresenter Name="PART_BottomCommandBar"
DockPanel.Dock="Bottom"
HorizontalContentAlignment="Stretch"
IsVisible="False" />
<ScrollViewer Padding="20"
HorizontalScrollBarVisibility="Disabled">
<ContentPresenter Name="PART_ContentPresenter"
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Content="{TemplateBinding Content}"
ContentTemplate="{TemplateBinding ContentTemplate}"
CornerRadius="{TemplateBinding CornerRadius}" />
</ScrollViewer>
</DockPanel>
</ControlTemplate>
</Setter>
</ControlTheme>
</ResourceDictionary>

157
samples/ControlCatalog/ViewModels/MainWindowViewModel.cs

@ -1,25 +1,27 @@
using Avalonia.Controls;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Controls.Chrome;
using Avalonia.Dialogs;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Runtime.CompilerServices;
using Avalonia;
using Avalonia.Collections;
using Avalonia.Controls;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Controls.Chrome;
using Avalonia.Dialogs;
using Avalonia.Media;
using Avalonia.Styling;
using ControlCatalog.Models;
using ControlCatalog.Pages;
using MiniMvvm;
namespace ControlCatalog.ViewModels
{
partial class MainWindowViewModel : ViewModelBase
{
private readonly AvaloniaList<PageItem> _filteredPages = [];
public SettingsViewModel SettingsViewModel { get; } = new SettingsViewModel();
private bool _ignoreListChange;
private PageItem? _currentItem;
public PageItem HomeItem { get; } = new PageItem("Home", () => new HomePage(), StreamGeometry.Parse(Icons.Home), "Overview of everything in the catalog", null);
public PageItem SettingsItem { get; }
public MainWindowViewModel()
{
@ -36,17 +38,29 @@ namespace ControlCatalog.ViewModels
{
(App.Current?.ApplicationLifetime as IClassicDesktopStyleApplicationLifetime)?.Shutdown();
});
NavigateToPageCommand = MiniCommand.Create<PageItem>(NavigateToPage);
SettingsItem = new PageItem("Settings", () => new SettingsPage(SettingsViewModel), StreamGeometry.Parse(Icons.Settings), "Overview of everything in the catalog", null);
NavigateToPageCommand = MiniCommand.Create<PageItem>(NavigateToItem);
SettingsCommand = MiniCommand.Create(async () =>
{
if (CurrentPageItem == SettingsItem)
return;
WindowState = WindowState.Normal;
if (Navigator is { } navigator)
{
NavigateToItem(SettingsItem);
}
});
WindowStates = new WindowState[]
HomeCommand = MiniCommand.Create(async () =>
{
WindowState.Minimized,
WindowState.Normal,
WindowState.Maximized,
WindowState.FullScreen,
};
if (CurrentPageItem == HomeItem)
return;
if (Navigator is { } navigator)
{
NavigateToItem(HomeItem);
}
});
TitleBarHeight = -1;
CanResize = true;
@ -60,8 +74,6 @@ namespace ControlCatalog.ViewModels
// Home page doesn't have a section title and should be excluded from this list
field ??= _pageSections.Where(s => !string.IsNullOrEmpty(s.Title)).ToArray();
public IReadOnlyList<PageItem> Pages => _filteredPages;
public INavigation? Navigator { get; internal set; }
public bool ExtendClientAreaEnabled
@ -76,55 +88,55 @@ namespace ControlCatalog.ViewModels
set => RaiseAndSetIfChanged(ref field, value);
}
public WindowState WindowState
public bool IsSystemBarVisible
{
get;
set => RaiseAndSetIfChanged(ref field, value);
}
public WindowState[] WindowStates
public bool DisplayEdgeToEdge
{
get;
set => RaiseAndSetIfChanged(ref field, value);
}
public bool IsSystemBarVisible
public Thickness SafeAreaPadding
{
get;
set => RaiseAndSetIfChanged(ref field, value);
}
public bool DisplayEdgeToEdge
public bool CanResize
{
get;
set => RaiseAndSetIfChanged(ref field, value);
}
public Thickness SafeAreaPadding
public bool CanMinimize
{
get;
set => RaiseAndSetIfChanged(ref field, value);
}
public bool CanResize
public bool CanMaximize
{
get;
set => RaiseAndSetIfChanged(ref field, value);
}
public bool CanMinimize
public bool ExpandAllSections
{
get;
set => RaiseAndSetIfChanged(ref field, value);
}
public bool CanMaximize
public string? OpenedSection
{
get;
set => RaiseAndSetIfChanged(ref field, value);
}
public int SelectedDecorationIndex
public ControlTheme? DecorationsTheme
{
get;
set => RaiseAndSetIfChanged(ref field, value);
@ -166,21 +178,10 @@ namespace ControlCatalog.ViewModels
set => SetTitleBarDecoration(TitleBarDecorations.CloseButton, value);
}
public int SelectedPageIndex
public PageItem? CurrentPageItem
{
get;
set
{
RaiseAndSetIfChanged(ref field, value);
if (!_ignoreListChange)
{
NavigateTo(field);
if (DisplayMode == SplitViewDisplayMode.CompactOverlay || DisplayMode == SplitViewDisplayMode.Overlay)
IsDrawerOpened = false;
}
}
set => RaiseAndSetIfChanged(ref field, value);
}
public bool IsDrawerOpened
@ -226,6 +227,10 @@ namespace ControlCatalog.ViewModels
public MiniCommand NavigateToPageCommand { get; }
public MiniCommand SettingsCommand { get; }
public MiniCommand HomeCommand { get; }
/// <summary>
/// A required DateTime which should demonstrate validation for the DateTimePicker
/// </summary>
@ -245,80 +250,60 @@ namespace ControlCatalog.ViewModels
set => RaiseAndSetIfChanged(ref field, value);
}
public void NavigateToPage(PageItem item)
public void NavigateToItem(PageItem item)
{
// Clear any active search so the target is present in the filtered list.
if (!string.IsNullOrEmpty(Query))
Query = "";
var index = _filteredPages.IndexOf(item);
if (index >= 0)
SelectedPageIndex = index;
NavigateTo(item);
}
public void Filter(string? query = "")
{
try
{
_ignoreListChange = true;
_filteredPages.Clear();
ExpandAllSections = false;
// Left panel items are sorted alphabetically
var allPages = _pageSections
.SelectMany(cat => cat.Items)
.OrderBy(p => p.Header == "Home" ? 0 : 1)
.ThenBy(p => p.Header);
// Left panel items are sorted alphabetically
var allPages = _pageSections
.SelectMany(cat => cat.Items?.ToArray() ?? Array.Empty<PageItem>())
.OrderBy(p => p.Header);
if (string.IsNullOrWhiteSpace(query))
{
_filteredPages.AddRange(allPages);
}
else
{
var querySearchKey = PageItem.CreateSearchKey(query);
var querySearchKey = query != null ? PageItem.CreateSearchKey(query) : "";
var isDefaultVisible = string.IsNullOrWhiteSpace(query) || string.IsNullOrWhiteSpace(querySearchKey);
if (querySearchKey.Length == 0)
{
_filteredPages.AddRange(allPages);
}
else
{
foreach (var item in allPages)
{
if (item.MatchesSearch(querySearchKey))
{
_filteredPages.Add(item);
}
}
}
}
foreach (var page in allPages)
{
page.IsVisible = isDefaultVisible;
}
finally
if (!string.IsNullOrWhiteSpace(querySearchKey))
{
_ignoreListChange = false;
if (_currentItem != null)
ExpandAllSections = true;
foreach (var item in allPages)
{
var newIndex = _filteredPages.IndexOf(_currentItem);
if (newIndex != -1)
if (item.MatchesSearch(querySearchKey))
{
SelectedPageIndex = newIndex;
item.IsVisible = true;
}
}
}
}
private async void NavigateTo(int pageIndex)
private async void NavigateTo(PageItem? item)
{
if (pageIndex < 0 || pageIndex >= Pages.Count || Navigator is null)
if (item is null || Navigator is null)
return;
var item = Pages[pageIndex];
var page = item.CreatePage();
if (page.GetType() != Navigator.NavigationStack.LastOrDefault()?.GetType())
if (item != CurrentPageItem)
{
_currentItem = item;
CurrentPageItem = item;
OpenedSection = item.Section;
await Navigator.ReplaceAsync(page);
if (DisplayMode == SplitViewDisplayMode.CompactOverlay || DisplayMode == SplitViewDisplayMode.Overlay)
IsDrawerOpened = false;
}
}
}

43
samples/ControlCatalog/ViewModels/MainWindowViewModel_PageList.cs

@ -1,10 +1,10 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Avalonia.Controls;
using ControlCatalog.Pages;
using Avalonia.Media;
using ControlCatalog.Models;
using System.Threading.Tasks;
using ControlCatalog.Pages;
namespace ControlCatalog.ViewModels;
@ -12,11 +12,7 @@ partial class MainWindowViewModel
{
private readonly HomeSection[] _pageSections =
[
Section("", s =>
{
s.Add<HomePage>("Home", Icons.Home, "Overview of everything in the catalog");
}),
Section("Basic Input", s =>
Section("Basic Input", Icons.Cursor2, s =>
{
s.Add<ButtonsPage>("Buttons", Icons.CursorClick, "Button, RepeatButton, ToggleButton and friends");
s.Add<ButtonSpinnerPage>("ButtonSpinner", Icons.Spinner, "Content with increment and decrement buttons");
@ -28,14 +24,14 @@ partial class MainWindowViewModel
s.Add<SliderPage>("Slider", Icons.Tune, "Select a value from a continuous range");
s.Add<ToggleSwitchPage>("ToggleSwitch", Icons.Toggle, "An on/off switch with a sliding knob");
}),
Section("Text", s =>
Section("Text", Icons.TextBox, s =>
{
s.Add<AutoCompleteBoxPage>("AutoCompleteBox", Icons.TextInput, "Text input with completion suggestions");
s.Add<LabelsPage>("Label", Icons.Tag, "Captions with access keys for other controls");
s.Add<TextBoxPage>("TextBox", Icons.TextInput, "Single- and multi-line text editing");
s.Add<TextBlockPage>("TextBlock", Icons.TextInput, "Styled read-only text display");
}),
Section("Collections & Data", s =>
Section("Collections & Data", Icons.Lists, s =>
{
s.Add<Pages.CarouselPage>("Carousel", Icons.Slides, "Cycle through a collection of items");
s.Add<ListBoxPage>("ListBox", Icons.List, "A selectable, virtualized list of items");
@ -44,13 +40,13 @@ partial class MainWindowViewModel
s.Add<TableViewPage>("TableView", Icons.Grid, "Tabular data with resizable, sortable columns");
s.Add<TreeViewPage>("TreeView", Icons.Tree, "Hierarchical data with expandable nodes");
}),
Section("Date & Time", s =>
Section("Date & Time", Icons.Date, s =>
{
s.Add<CalendarPage>("Calendar", Icons.Calendar, "A month calendar for selecting dates");
s.Add<CalendarDatePickerPage>("CalendarDatePicker", Icons.Calendar, "A date picker with a drop-down calendar");
s.Add<DateTimePickerPage>("Date/Time Picker", Icons.Clock, "Spinner-style date and time pickers");
}),
Section("Menus & Flyouts", s =>
Section("Menus & Flyouts", Icons.Menus, s =>
{
s.Add<CommandBarPage>("CommandBar", Icons.Terminal, "A toolbar of commands with an overflow menu");
s.Add<ContextFlyoutPage>("ContextFlyout", Icons.Menu, "Attach flyouts shown on right-click");
@ -58,7 +54,7 @@ partial class MainWindowViewModel
s.Add<FlyoutsPage>("Flyouts", Icons.Flyout, "Lightweight popups anchored to controls");
s.Add<MenuPage>("Menu", Icons.Menu, "Menu bars with nested menu items");
}),
Section("Navigation & Pages", s =>
Section("Navigation & Pages", Icons.HamburgerUnread, s =>
{
s.Add<CarouselDemoPage>("CarouselPage", Icons.Slides, "Swipeable page-based navigation");
s.Add<ContentDemoPage>("ContentPage", Icons.Document, "A page that hosts a single content view");
@ -69,7 +65,7 @@ partial class MainWindowViewModel
s.Add<TabControlPage>("TabControl", Icons.Tab, "Switch between tabbed content views");
s.Add<TabStripPage>("TabStrip", Icons.Tab, "A standalone strip of selectable tabs");
}),
Section("Layout", s =>
Section("Layout", Icons.Layouts, s =>
{
s.Add<BorderPage>("Border", Icons.Border, "Decorate elements with borders and corner radii");
s.Add<CanvasPage>("Canvas", Icons.Canvas, "Position children at explicit coordinates");
@ -83,7 +79,7 @@ partial class MainWindowViewModel
s.Add<ViewboxPage>("Viewbox", Icons.Viewbox, "Scale content to fit available space");
s.Add<WrapPanelPage>("WrapPanel", Icons.Layout, "Wrap children onto multiple lines");
}),
Section("Media & Graphics", s =>
Section("Media & Graphics", Icons.Media, s =>
{
s.Add<AcrylicPage>("Acrylic", Icons.Blur, "Translucent acrylic window materials");
s.Add<BitmapCachePage>("BitmapCache", Icons.Lightning, "Cache visuals as bitmaps for performance");
@ -94,7 +90,7 @@ partial class MainWindowViewModel
s.Add<OpenGlLeasePage>("OpenGL Lease", Icons.Cube3D, "Low-level access to the OpenGL context");
s.Add<TransitioningContentControlPage>("TransitioningContentControl", Icons.Transition, "Animate between content changes");
}),
Section("Status & Feedback", s =>
Section("Status & Feedback", Icons.Chat, s =>
{
s.Add<AdornerLayerPage>("AdornerLayer", Icons.Sparkle, "Overlay visuals on top of other controls");
s.Add<DataValidationPage>("Data Validation", Icons.Shield, "Display validation errors from bindings");
@ -103,7 +99,7 @@ partial class MainWindowViewModel
s.Add<ProgressBarPage>("ProgressBar", Icons.Progress, "Determinate and indeterminate progress");
s.Add<ToolTipPage>("ToolTip", Icons.Tooltip, "Hover hints for any control");
}),
Section("Interaction", s =>
Section("Interaction", Icons.KeyboardFloat, s =>
{
s.Add<AcceleratorPage>("Accelerator", Icons.Keyboard, "Keyboard shortcuts that invoke commands");
s.Add<ClipboardPage>("Clipboard", Icons.Clipboard, "Read from and write to the system clipboard");
@ -113,7 +109,7 @@ partial class MainWindowViewModel
s.Add<GesturePage>("Gestures", Icons.Gesture, "Tap, scroll and pinch gesture recognition");
s.Add<PointersPage>("Pointers", Icons.Cursor, "Raw pointer input and capture");
}),
Section("Window & Platform", s =>
Section("Window & Platform", Icons.DesktopMobile, s =>
{
s.Add<NativeEmbedPage>("Native Embed", Icons.Puzzle, "Host native platform controls");
s.Add<PlatformInfoPage>("Platform Information", Icons.Info, "Runtime platform and capability info");
@ -124,19 +120,22 @@ partial class MainWindowViewModel
})
];
private static HomeSection Section(string title, Action<HomeSectionBuilder> builderCallback)
private static HomeSection Section(string title, string iconPath, Action<HomeSectionBuilder> builderCallback)
{
var builder = new HomeSectionBuilder(title);
var iconGeometry = StreamGeometry.Parse(iconPath);
var section = new HomeSection(title, iconGeometry);
var builder = new HomeSectionBuilder(section);
builderCallback(builder);
return new HomeSection(title, builder.ToArray());
section.Items = builder.ToArray();
return section;
}
private class HomeSectionBuilder(string title) : List<PageItem>
private class HomeSectionBuilder(HomeSection section) : List<PageItem>
{
public void Add<TPageType>(string header, string iconPath, string description) where TPageType : Page, new()
{
var iconGeometry = StreamGeometry.Parse(iconPath);
Add(new PageItem(header, () => new TPageType(), iconGeometry, description, title));
Add(new PageItem(header, () => new TPageType(), iconGeometry, description, section));
}
public async virtual Task Navigate(INavigation navigation) { }

10
samples/ControlCatalog/ViewModels/SectionViewModel.cs

@ -0,0 +1,10 @@
using ControlCatalog.Models;
using MiniMvvm;
namespace ControlCatalog.ViewModels
{
internal class SectionViewModel(HomeSection homeSection) : ViewModelBase
{
public HomeSection HomeSection { get; } = homeSection;
}
}

57
samples/ControlCatalog/ViewModels/SettingsViewModel.cs

@ -0,0 +1,57 @@
using Avalonia.Controls;
using MiniMvvm;
namespace ControlCatalog.ViewModels
{
public class SettingsViewModel : ViewModelBase
{
public SettingsViewModel()
{
WindowStates = new WindowState[]
{
WindowState.Minimized,
WindowState.Normal,
WindowState.Maximized,
WindowState.FullScreen,
};
WindowState = WindowState.Normal;
}
public WindowState WindowState
{
get;
set => RaiseAndSetIfChanged(ref field, value);
}
public int SelectedDecorationIndex
{
get;
set => RaiseAndSetIfChanged(ref field, value);
}
public int SelectedThemeVariantIndex
{
get;
set => RaiseAndSetIfChanged(ref field, value);
}
public int SelectedTransparencyLevelIndex
{
get;
set => RaiseAndSetIfChanged(ref field, value);
}
public int SelectedFlowDirectionIndex
{
get;
set => RaiseAndSetIfChanged(ref field, value);
}
public WindowState[] WindowStates
{
get;
set => RaiseAndSetIfChanged(ref field, value);
}
}
}
Loading…
Cancel
Save