feat: add header footer to navmenu.

This commit is contained in:
rabbitism
2024-02-14 00:41:33 +08:00
parent ec41a8228f
commit 32f5662370
4 changed files with 97 additions and 69 deletions

View File

@@ -15,69 +15,77 @@
<UserControl.Resources> <UserControl.Resources>
<converters:IconNameToPathConverter x:Key="IconConverter"/> <converters:IconNameToPathConverter x:Key="IconConverter"/>
</UserControl.Resources> </UserControl.Resources>
<ScrollViewer> <Grid ColumnDefinitions="Auto, Auto" RowDefinitions="Auto, Auto, *" HorizontalAlignment="Left">
<StackPanel HorizontalAlignment="Left"> <ToggleButton Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2" Name="collapse">Collapse</ToggleButton>
<TextBlock Text="{ReflectionBinding #menu2.SelectedItem.Header}"></TextBlock> <TextBlock Grid.Row="1" Grid.Column="0" Text="{ReflectionBinding #menu.SelectedItem.Header}" />
<u:NavMenu Name="menu2" Width="300" IsHorizontalCollapsed="{Binding #collapse.IsChecked}"> <Border Grid.Row="2" Grid.Column="0" Theme="{DynamicResource CardBorder}" HorizontalAlignment="Left" Padding="0">
<u:NavMenuItem Header="Menu 1"> <u:NavMenu
<u:NavMenuItem.Icon> Header="Hello Ursa"
<Rectangle Name="menu"
Width="10" HeaderBinding="{Binding Header}"
Height="10" IconBinding="{Binding IconIndex}"
Fill="Red" /> IsHorizontalCollapsed="{Binding #collapse.IsChecked, Mode=OneWay}"
</u:NavMenuItem.Icon> ItemsSource="{Binding MenuItems}"
<u:NavMenuItem Header="Sub Menu 1"></u:NavMenuItem> SubMenuBinding="{Binding Children}">
<u:NavMenuItem Header="Sub Menu 2"></u:NavMenuItem> <u:NavMenu.IconTemplate>
<u:NavMenuItem Header="Sub Menu 3"></u:NavMenuItem> <DataTemplate DataType="{x:Type x:Int32}">
</u:NavMenuItem> <u:TwoTonePathIcon
<u:NavMenuItem Header="Menu 2"> Width="16"
<u:NavMenuItem.Icon> Height="16"
<Rectangle Data="{Binding Converter={StaticResource IconConverter}}"
Width="20" StrokeBrush="{DynamicResource SemiGrey5}"
Height="10" Foreground="{DynamicResource SemiGrey5}"
Fill="Red" /> ActiveStrokeBrush="{DynamicResource SemiBlue5}"
</u:NavMenuItem.Icon> ActiveForeground="{DynamicResource SemiBlue5}"
</u:NavMenuItem> IsActive="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=u:NavMenuItem}, Path=IsHighlighted, Mode=TwoWay}">
<u:NavMenuItem Header="Menu 3"> </u:TwoTonePathIcon>
<u:NavMenuItem.Icon> </DataTemplate>
<Rectangle </u:NavMenu.IconTemplate>
Width="30" <u:NavMenu.Footer>
Height="10" <Button>Collapse</Button>
Fill="Red" /> </u:NavMenu.Footer>
</u:NavMenuItem.Icon>
</u:NavMenuItem>
</u:NavMenu> </u:NavMenu>
<u:Divider Content="Divider" /> </Border>
<TextBlock Grid.Row="1" Grid.Column="1" Text="{ReflectionBinding #menu2.SelectedItem.Header}"></TextBlock>
<u:NavMenu Grid.Row="2" Grid.Column="1" Name="menu2" IsHorizontalCollapsed="{Binding #collapse.IsChecked}">
<u:NavMenuItem Header="Menu 1">
<u:NavMenuItem.Icon>
<Rectangle
Width="10"
Height="10"
Fill="Red" />
</u:NavMenuItem.Icon>
<u:NavMenuItem Header="Sub Menu 1"></u:NavMenuItem>
<u:NavMenuItem Header="Sub Menu 2"></u:NavMenuItem>
<u:NavMenuItem Header="Sub Menu 3"></u:NavMenuItem>
</u:NavMenuItem>
<u:NavMenuItem Header="Menu 2">
<u:NavMenuItem.Icon>
<Rectangle
Width="10"
Height="10"
Fill="Red" />
</u:NavMenuItem.Icon>
</u:NavMenuItem>
<u:NavMenuItem Header="Menu 3">
<u:NavMenuItem.Icon>
<Rectangle
Width="10"
Height="10"
Fill="Red" />
</u:NavMenuItem.Icon>
</u:NavMenuItem>
</u:NavMenu>
<StackPanel HorizontalAlignment="Left">
<TextBlock Text="{ReflectionBinding #menu.SelectedItem.Header}" />
<ToggleButton Name="collapse">Collapse</ToggleButton>
<Border Theme="{DynamicResource CardBorder}" HorizontalAlignment="Left" Padding="0">
<u:NavMenu
Name="menu"
HeaderBinding="{Binding Header}"
IconBinding="{Binding IconIndex}"
IsHorizontalCollapsed="{Binding #collapse.IsChecked, Mode=OneWay}"
ItemsSource="{Binding MenuItems}"
SubMenuBinding="{Binding Children}">
<u:NavMenu.IconTemplate>
<DataTemplate DataType="{x:Type x:Int32}">
<u:TwoTonePathIcon
Width="18"
Height="18"
Data="{Binding Converter={StaticResource IconConverter}}"
StrokeBrush="{DynamicResource SemiBlue2}"
Foreground="{DynamicResource SemiBlue2}"
ActiveStrokeBrush="{DynamicResource SemiBlue6}"
ActiveForeground="{DynamicResource SemiBlue6}"
IsActive="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=u:NavMenuItem}, Path=IsHighlighted, Mode=TwoWay}">
</u:TwoTonePathIcon>
</DataTemplate>
</u:NavMenu.IconTemplate>
</u:NavMenu>
</Border>
</StackPanel> </StackPanel>
</ScrollViewer> </Grid>
</UserControl> </UserControl>

View File

@@ -12,9 +12,13 @@
<Setter Property="SubMenuIndent" Value="24" /> <Setter Property="SubMenuIndent" Value="24" />
<Setter Property="Template"> <Setter Property="Template">
<ControlTemplate TargetType="u:NavMenu"> <ControlTemplate TargetType="u:NavMenu">
<ScrollViewer HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto"> <DockPanel LastChildFill="True">
<ItemsPresenter ItemsPanel="{TemplateBinding ItemsPanel}" /> <ContentPresenter Content="{TemplateBinding Header}" DockPanel.Dock="Top"></ContentPresenter>
</ScrollViewer> <ContentPresenter Content="{TemplateBinding Footer}" DockPanel.Dock="Bottom"></ContentPresenter>
<ScrollViewer HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto">
<ItemsPresenter ItemsPanel="{TemplateBinding ItemsPanel}" />
</ScrollViewer>
</DockPanel>
</ControlTemplate> </ControlTemplate>
</Setter> </Setter>
<Style Selector="^:horizontal-collapsed"> <Style Selector="^:horizontal-collapsed">

View File

@@ -5,6 +5,7 @@ using Avalonia.Controls.Metadata;
using Avalonia.Controls.Primitives; using Avalonia.Controls.Primitives;
using Avalonia.Data; using Avalonia.Data;
using Avalonia.Media; using Avalonia.Media;
using Irihi.Avalonia.Shared.Helpers;
namespace Ursa.Controls; namespace Ursa.Controls;
@@ -75,13 +76,7 @@ public class TwoTonePathIcon: TemplatedControl
ForegroundProperty, ForegroundProperty,
ActiveForegroundProperty, ActiveForegroundProperty,
ActiveStrokeBrushProperty); ActiveStrokeBrushProperty);
IsActiveProperty.Changed.AddClassHandler<TwoTonePathIcon, bool>((o, e) => o.OnIsActiveChanged(e)); PropertyToPseudoClassMixin.Attach<TwoTonePathIcon>(IsActiveProperty, PC_Active);
}
private void OnIsActiveChanged(AvaloniaPropertyChangedEventArgs<bool> args)
{
var newValue = args.NewValue.Value;
PseudoClasses.Set(PC_Active, newValue);
} }
protected override void OnApplyTemplate(TemplateAppliedEventArgs e) protected override void OnApplyTemplate(TemplateAppliedEventArgs e)

View File

@@ -72,6 +72,9 @@ public class NavMenu: ItemsControl
public static readonly StyledProperty<IDataTemplate?> HeaderTemplateProperty = AvaloniaProperty.Register<NavMenu, IDataTemplate?>( public static readonly StyledProperty<IDataTemplate?> HeaderTemplateProperty = AvaloniaProperty.Register<NavMenu, IDataTemplate?>(
nameof(HeaderTemplate)); nameof(HeaderTemplate));
/// <summary>
/// Header Template is used for MenuItem headers, not menu header.
/// </summary>
public IDataTemplate? HeaderTemplate public IDataTemplate? HeaderTemplate
{ {
get => GetValue(HeaderTemplateProperty); get => GetValue(HeaderTemplateProperty);
@@ -105,6 +108,24 @@ public class NavMenu: ItemsControl
set => SetValue(IsHorizontalCollapsedProperty, value); set => SetValue(IsHorizontalCollapsedProperty, value);
} }
public static readonly StyledProperty<object?> HeaderProperty =
HeaderedContentControl.HeaderProperty.AddOwner<NavMenu>();
public object? Header
{
get => GetValue(HeaderProperty);
set => SetValue(HeaderProperty, value);
}
public static readonly StyledProperty<object?> FooterProperty = AvaloniaProperty.Register<NavMenu, object?>(
nameof(Footer));
public object? Footer
{
get => GetValue(FooterProperty);
set => SetValue(FooterProperty, value);
}
static NavMenu() static NavMenu()
{ {
SelectedItemProperty.Changed.AddClassHandler<NavMenu, object?>((o, e) => o.OnSelectedItemChange(e)); SelectedItemProperty.Changed.AddClassHandler<NavMenu, object?>((o, e) => o.OnSelectedItemChange(e));