预览
未折叠时
折叠时
点击菜单,显示对应的界面
资源网站
一般图标我是从以下两个网站寻找的。
第一个 (Material Design Icons - Icon Library - Pictogrammers)
例如这里 home 的第一个图标,点击后有详细页面,你可以复制为前端 React、Vue 等框架的样式,
或者也可以复制 SVG 代码,如果你和我一样是放在 avalonia 里的图标样式资源文件中,你只需要将复制的 SVG 代码的 path - d 属性的内容复制到 avalonia 样式文件里的 StreamGeometry 中。
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
<title>home-account</title>
<path d="M12,3L2,12H5V20H19V12H22L12,3M12,8.75A2.25,2.25 0 0,1 14.25,11A2.25,2.25 0 0,1 12,13.25A2.25,2.25 0 0,1 9.75,11A2.25,2.25 0 0,1 12,8.75M12,15C13.5,15 16.5,15.75 16.5,17.25V18H7.5V17.25C7.5,15.75 10.5,15 12,15Z" />
</svg>
我们只需要
M12,3L2,12H5V20H19V12H22L12,3M12,8.75A2.25,2.25 0 0,1 14.25,11A2.25,2.25 0 0,1 12,13.25A2.25,2.25 0 0,1 9.75,11A2.25,2.25 0 0,1 12,8.75M12,15C13.5,15 16.5,15.75 16.5,17.25V18H7.5V17.25C7.5,15.75 10.5,15 12,15Z
第二个网站,iconfont-阿里巴巴矢量图标库
同样是 home 图标,你也可以自定义颜色和大小后复制 SVG 代码,然后取得 d 的内容。
项目目录树结构
一些不必要的目录以省略。
F:.
├─Assets
├─Models
├─ViewModels
└─Views
引入图标
我们在 Assets 下创建 Icons.axaml Styles 文件。
<Styles xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style>
<Style.Resources>
<StreamGeometry x:Key="HomeIcon">M21.6062 5.85517C23.0048 4.71494 24.9952 4.71494 26.3938 5.85517L39.5688 16.5966C40.4736 17.3342 41 18.4492 41 19.628V39.1134C41 41.2599 39.2875 43 37.175 43H32.075C29.9625 43 28.25 41.2599 28.25 39.1134V29.7492C28.25 29.0337 27.6792 28.4536 26.975 28.4536H21.025C20.3208 28.4536 19.75 29.0337 19.75 29.7492V39.1134C19.75 41.2599 18.0375 43 15.925 43H10.825C8.71251 43 7 41.2599 7 39.1134V19.628C7 18.4493 7.52645 17.3342 8.43124 16.5966L21.6062 5.85517ZM24.7979 7.87612C24.3317 7.49604 23.6683 7.49604 23.2021 7.87612L10.0271 18.6175C9.72548 18.8634 9.55 19.2351 9.55 19.628V39.1134C9.55 39.8289 10.1208 40.4089 10.825 40.4089H15.925C16.6292 40.4089 17.2 39.8289 17.2 39.1134V29.7492C17.2 27.6027 18.9125 25.8626 21.025 25.8626H26.975C29.0875 25.8626 30.8 27.6027 30.8 29.7492V39.1134C30.8 39.8289 31.3708 40.4089 32.075 40.4089H37.175C37.8792 40.4089 38.45 39.8289 38.45 39.1134V19.628C38.45 19.2351 38.2745 18.8634 37.9729 18.6175L24.7979 7.87612Z</StreamGeometry>
<StreamGeometry x:Key="MenuIcon">M2 4.5C2 4.22386 2.22386 4 2.5 4H17.5C17.7761 4 18 4.22386 18 4.5C18 4.77614 17.7761 5 17.5 5H2.5C2.22386 5 2 4.77614 2 4.5Z M2 9.5C2 9.22386 2.22386 9 2.5 9H17.5C17.7761 9 18 9.22386 18 9.5C18 9.77614 17.7761 10 17.5 10H2.5C2.22386 10 2 9.77614 2 9.5Z M2.5 14C2.22386 14 2 14.2239 2 14.5C2 14.7761 2.22386 15 2.5 15H17.5C17.7761 15 18 14.7761 18 14.5C18 14.2239 17.7761 14 17.5 14H2.5Z</StreamGeometry>
<StreamGeometry x:Key="SettingIcon">M12,8A4,4 0 0,1 16,12A4,4 0 0,1 12,16A4,4 0 0,1 8,12A4,4 0 0,1 12,8M12,10A2,2 0 0,0 10,12A2,2 0 0,0 12,14A2,2 0 0,0 14,12A2,2 0 0,0 12,10M10,22C9.75,22 9.54,21.82 9.5,21.58L9.13,18.93C8.5,18.68 7.96,18.34 7.44,17.94L4.95,18.95C4.73,19.03 4.46,18.95 4.34,18.73L2.34,15.27C2.21,15.05 2.27,14.78 2.46,14.63L4.57,12.97L4.5,12L4.57,11L2.46,9.37C2.27,9.22 2.21,8.95 2.34,8.73L4.34,5.27C4.46,5.05 4.73,4.96 4.95,5.05L7.44,6.05C7.96,5.66 8.5,5.32 9.13,5.07L9.5,2.42C9.54,2.18 9.75,2 10,2H14C14.25,2 14.46,2.18 14.5,2.42L14.87,5.07C15.5,5.32 16.04,5.66 16.56,6.05L19.05,5.05C19.27,4.96 19.54,5.05 19.66,5.27L21.66,8.73C21.79,8.95 21.73,9.22 21.54,9.37L19.43,11L19.5,12L19.43,13L21.54,14.63C21.73,14.78 21.79,15.05 21.66,15.27L19.66,18.73C19.54,18.95 19.27,19.04 19.05,18.95L16.56,17.95C16.04,18.34 15.5,18.68 14.87,18.93L14.5,21.58C14.46,21.82 14.25,22 14,22H10M11.25,4L10.88,6.61C9.68,6.86 8.62,7.5 7.85,8.39L5.44,7.35L4.69,8.65L6.8,10.2C6.4,11.37 6.4,12.64 6.8,13.8L4.68,15.36L5.43,16.66L7.86,15.62C8.63,16.5 9.68,17.14 10.87,17.38L11.24,20H12.76L13.13,17.39C14.32,17.14 15.37,16.5 16.14,15.62L18.57,16.66L19.32,15.36L17.2,13.81C17.6,12.64 17.6,11.37 17.2,10.2L19.31,8.65L18.56,7.35L16.15,8.39C15.38,7.5 14.32,6.86 13.12,6.62L12.75,4H11.25Z</StreamGeometry>
</Style.Resources>
</Style>
</Styles>
key 是用来区分资源的代号,以后你有其它的资源放入到 Style.Resources 即可,不断地定义 StreamGeometry。
然后在 App.axaml 引入图标资源
<Application.Styles>
<FluentTheme />
<StyleInclude Source="Assets/Icons.axaml"></StyleInclude>
</Application.Styles>
ViewModelBase 这里我用的是 COmmunityToolkit.Mvvm,而不是默认的 ReactiveUI
using CommunityToolkit.Mvvm.ComponentModel;
namespace Avalonia_MVVM_SideMenu.ViewModels;
public class ViewModelBase : ObservableObject
{
}
HomeViewModel,创建在 ViewModels 文件夹下。
namespace Avalonia_MVVM_SideMenu.ViewModels;
public class HomeViewModel:ViewModelBase
{
}
SettingViewModel,创建在 ViewModels 文件夹下。
namespace Avalonia_MVVM_SideMenu.ViewModels;
public class SettingViewModel:ViewModelBase
{
}
在创建 Views 文件夹下创建 UserControl 类别的 文件 HomeView 和 SettingView。
一定是这样的命名,这与我们的绑定方式有关,见MainWindowViewModel处的代码
MainWindowViewModel
using System;
using System.Collections.ObjectModel;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Media;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
namespace Avalonia_MVVM_SideMenu.ViewModels;
public partial class MainWindowViewModel : ViewModelBase
{
[ObservableProperty] public ViewModelBase _currentPage = new HomeViewModel();
[ObservableProperty] public bool _isPaneOpen = true;
[ObservableProperty] public ListItemTemplate? _selectedListItem;
public ObservableCollection<ListItemTemplate> Items { get; } = new()
{
new ListItemTemplate(typeof(HomeViewModel), "HomeIcon", "主页"),
new ListItemTemplate(typeof(SettingViewModel), "SettingIcon", "设置")
};
partial void OnSelectedListItemChanged(ListItemTemplate? value)
{
if (value is null) return;
var instance = Activator.CreateInstance(value.ModelType);
if (instance is null) return;
CurrentPage = (ViewModelBase)instance;
}
[RelayCommand]
private void TriggerPane()
{
IsPaneOpen = !IsPaneOpen;
}
}
public class ListItemTemplate
{
public ListItemTemplate(Type type, string iconKey, string name)
{
ModelType = type;
Label = name;
// Label = type.Name.Replace("ViewModel", "");
Label = type.Name.Replace("ViewModel", "");
Application.Current!.TryFindResource(iconKey, out var res);
ListItemIcon = (StreamGeometry)res!;
}
public string Label { get; }
public Type ModelType { get; }
public StreamGeometry ListItemIcon { get; }
}
创建对应的 HomeView 和 SettingView 的User Control,命名为 HomeView 和 SettingView
MainWindow
<Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="using:Avalonia_MVVM_SideMenu.ViewModels"
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"
x:Class="Avalonia_MVVM_SideMenu.Views.MainWindow"
x:DataType="vm:MainWindowViewModel"
Icon="/Assets/avalonia-logo.ico"
Title="Avalonia_MVVM_SideMenu">
<Design.DataContext>
<vm:MainWindowViewModel />
</Design.DataContext>
<SplitView IsPaneOpen="{Binding IsPaneOpen}"
OpenPaneLength="200"
DisplayMode="CompactInline"
Margin="12,12,12,12"
CompactPaneLength="48">
<SplitView.Pane>
<StackPanel Spacing="5"
Margin="5">
<Button Command="{Binding TriggerPaneCommand}">
<PathIcon Data="{StaticResource MenuIcon}" />
</Button>
<ListBox ItemsSource="{Binding Items}" SelectedItem="{Binding SelectedListItem}">
<ListBox.ItemTemplate>
<DataTemplate DataType="{x:Type vm:ListItemTemplate}">
<StackPanel Spacing="15" Orientation="Horizontal" Margin="0,0">
<PathIcon Data="{Binding ListItemIcon}" />
<TextBlock Text="{Binding Label}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</StackPanel>
</SplitView.Pane>
<SplitView.Content>
<Border CornerRadius="12 0 0 0">
<TransitioningContentControl Content="{Binding CurrentPage}" />
</Border>
</SplitView.Content>
</SplitView>
</Window>