.Net-Avalonia学习笔记(八)-音乐商店应用(MVVM+IOC/ID)

一、音乐商店应用

  该应用程序具有高度图形化的界面,显示专辑封面图像,并使用半透明的“亚克力”效果模糊窗口背景,使其具有非常时尚的外观。在本教程结束时,您将能够搜索 iTunes 在线专辑列表,并选择专辑添加到您自己的列表中。

  官方项目地址:https://docs.avaloniaui.net/zh-Hans/docs/tutorials/music-store-app/

1、创建项目

(1)新建解决方案
(2)选择Avalonia .NET Core MVVM App

(3)解决方案名为 “Avalonia_MusicStore”,下一步然后点击“创建”

(4)新项目大体目录如下:

2、实现亚克力风格

(1)改为暗色模式(可选)

  找到App.axaml,将 <Application> 元素中的 RequestedThemeVariant 属性从 Default 更改为 Dark

<Application xmlns="https://github.com/avaloniaui"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             x:Class="Avalonia_MusicStore.App"
             xmlns:local="using:Avalonia_MusicStore"
             RequestedThemeVariant="Default">
             <!-- "Default" ThemeVariant follows system theme variant. "Dark" or "Light" are other available options. -->
...
(2)改为亚克力模糊

  找到 /Views/MainWindow.axaml 文件,在<Window>中添加新属性TransparencyLevelHint="AcrylicBlur"Background="Transparent";效果如下:

(3)将毛玻璃效果拓展到标题栏

  在 /Views/MainWindow.axaml 文件的<Window>中添加属性ExtendClientAreaToDecorationsHint="True"即可;效果如下:

3、实现专辑列表

(1)主页跳转按钮样式

  实现专辑列表前,要现在窗体主页中添加一个跳转到‘专辑列表’的按钮,样式如下:

  

  代码如下:

<Window xmlns="https://github.com/avaloniaui"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:vm="using:Avalonia_MusicStore.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_MusicStore.Views.MainWindow"
        x:DataType="vm:MainWindowViewModel"
        Icon="/Assets/avalonia-logo.ico"
        Title="Avalonia_音乐商店" 
		TransparencyLevelHint="AcrylicBlur" Background="Transparent"
		ExtendClientAreaToDecorationsHint="True">
    <Design.DataContext>
        <!-- This only sets the DataContext for the previewer in an IDE,
             to set the actual DataContext for runtime, set the DataContext property in code (look at App.axaml.cs) -->
        <vm:MainWindowViewModel/>
    </Design.DataContext>

	<Panel Margin="40">
		<Button Content="BuyMusic"
		   HorizontalAlignment="Right" VerticalAlignment="Top" >
			<PathIcon Data="{StaticResource store_microsoft_regular}" />
		</Button>
	</Panel>
</Window>
(2)跳转按钮图标

  Microsoft Store 图标取自:https://avaloniaui.github.io/icons.html;代码为

<StreamGeometry x:Key="store_microsoft_regular">M11.5 9.5V13H8V9.5H11.5Z M11.5 17.5V14H8V17.5H11.5Z M16 9.5V13H12.5V9.5H16Z M16 17.5V14H12.5V17.5H16Z M8 6V3.75C8 2.7835 8.7835 2 9.75 2H14.25C15.2165 2 16 2.7835 16 3.75V6H21.25C21.6642 6 22 6.33579 22 6.75V18.25C22 19.7688 20.7688 21 19.25 21H4.75C3.23122 21 2 19.7688 2 18.25V6.75C2 6.33579 2.33579 6 2.75 6H8ZM9.5 3.75V6H14.5V3.75C14.5 3.61193 14.3881 3.5 14.25 3.5H9.75C9.61193 3.5 9.5 3.61193 9.5 3.75ZM3.5 18.25C3.5 18.9404 4.05964 19.5 4.75 19.5H19.25C19.9404 19.5 20.5 18.9404 20.5 18.25V7.5H3.5V18.25Z</StreamGeometry>

 a. 创建图标样式文件

  工程->新建类->创建AvaloniaStyle文件,名称为IconsStyles.axaml,代码如下:

<Styles xmlns="https://github.com/avaloniaui"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
  <Design.PreviewWith>
    <Border Padding="20">
      <!-- Add Controls for Previewer Here -->
    </Border>
  </Design.PreviewWith>

  <!-- Add Styles Here -->
	<Style>
		<Style.Resources>
			<StreamGeometry x:Key="store_microsoft_regular">M11.5 9.5V13H8V9.5H11.5Z M11.5 17.5V14H8V17.5H11.5Z M16 9.5V13H12.5V9.5H16Z M16 17.5V14H12.5V17.5H16Z M8 6V3.75C8 2.7835 8.7835 2 9.75 2H14.25C15.2165 2 16 2.7835 16 3.75V6H21.25C21.6642 6 22 6.33579 22 6.75V18.25C22 19.7688 20.7688 21 19.25 21H4.75C3.23122 21 2 19.7688 2 18.25V6.75C2 6.33579 2.33579 6 2.75 6H8ZM9.5 3.75V6H14.5V3.75C14.5 3.61193 14.3881 3.5 14.25 3.5H9.75C9.61193 3.5 9.5 3.61193 9.5 3.75ZM3.5 18.25C3.5 18.9404 4.05964 19.5 4.75 19.5H19.25C19.9404 19.5 20.5 18.9404 20.5 18.25V7.5H3.5V18.25Z</StreamGeometry>
		</Style.Resources>
	</Style>
</Styles>

 b. 将图标资源添加到工程资源中

  打开 App.axaml 文件,添加一个 <StyleInclude> 元素,如下所示:

<Application.Styles>
    <FluentTheme />
    <StyleInclude Source="avares://Avalonia_MusicStore/IconsStyles.axaml" />
</Application.Styles>
(3)按钮事件(MVVM;CommunityToolkit.Mvvm)

  这里使用CommunityToolkit.Mvvm+依赖注入,官方示例使用的ReactiveUI。

 a. 搜索App.cs,添加依赖注入的方法,先阶段完整代码如下:

using System;
using Avalonia;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Data.Core;
using Avalonia.Data.Core.Plugins;
using Avalonia.Markup.Xaml;
using Avalonia_MusicStore.ViewModels;
using Avalonia_MusicStore.Views;
using Microsoft.Extensions.DependencyInjection;   // .NET Core内置依赖注入模块。
using CommunityToolkit.Mvvm.DependencyInjection;  // mvvm框架的内置的依赖注入模块。
using Avalonia_MusicStore.Models;


namespace Avalonia_MusicStore
{
    public partial class App : Application
    {
        #region
        public new static App Current => (App)Application.Current;
        public IServiceProvider Services { get; set; }
        #endregion 

        public override void Initialize()
        {
            AvaloniaXamlLoader.Load(this);
        }

        public override void OnFrameworkInitializationCompleted()
        {
            if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
            {
                Services = ServiceCollection();

                // Line below is needed to remove Avalonia data validation. Without this line you will get duplicate validations from both Avalonia and CT
                BindingPlugins.DataValidators.RemoveAt(0);

                desktop.MainWindow = Services.GetService<MainWindowView>();
                {
                    DataContext = Services.GetService<MainWindowViewModel>();
                };
            }

            base.OnFrameworkInitializationCompleted();
        }

        /// <summary>
        /// 注册服务
        /// </summary>
        /// <returns></returns>
        private static IServiceProvider ServiceCollection()
        {
            var service = new ServiceCollection();

            //service.AddSingleton<Album>();

            service.AddSingleton<MainWindowViewModel>();
            //service.AddSingleton<MusicStoreWindowViewModel>();
            //service.AddSingleton<MusicStoreViewModel>();
            //service.AddSingleton<AlbumViewModel>();

            service.AddSingleton<MainWindowView>();
            //service.AddSingleton<MusicStoreWindowView>();

            return service.BuildServiceProvider();
        }
    }
}

 b. 搜索MainWindowViewModel.cs,添加BuyMusicCommand方法,完整代码如下:

using CommunityToolkit.Mvvm.Input;
using System.Diagnostics;
using System.Threading.Tasks;

namespace Avalonia_MusicStore.ViewModels
{
    public partial class MainWindowViewModel : ViewModelBase
    {
        /// <summary>
        /// 购买音乐 按钮
        /// </summary>
        /// <returns></returns>
        [RelayCommand]
        public void BuyMusic()
        {
            Debug.WriteLine("购买音乐");
            MusicStoreWindowViewModel musicStoreWindowVM = App.Current.Services.GetService<MusicStoreWindowViewModel>();
            //musicStoreWindowVM.Show();

            MainWindowView mainWindow = App.Current.Services.GetService<MainWindowView>();
            musicStoreWindowVM.ShowDialog(mainWindow);
        }
    }
}

  c. 在MainWindow.axaml中的Button按钮中添加属性Command="{Binding BuyMusicCommand}";代码如下:

	<Panel Margin="40">
		<Button Content="BuyMusic"
		   HorizontalAlignment="Right" VerticalAlignment="Top" Command="{Binding BuyMusicCommand}">
			<PathIcon Data="{StaticResource store_microsoft_regular}" />
		</Button>
	</Panel>

4、音乐商店对话框(MusicStoreWindow)

(1)添加窗体
  • 在解决方案资源管理器中,右键单击 /Views 文件夹;
  • 点击 添加 Avalonia Window
  • 输入名称 'MusicStoreWindow'
  • 添加 亚克力模糊背景,并将其延伸到标题栏(与之前相同)
  •  /ViewModels 文件夹添加 MusicStoreViewModel.cs,代码如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Avalonia_MusicStore.ViewModels
{
    /// <summary>
    /// 音乐商店窗体ViewModel
    /// </summary>
    public partial class MusicStoreViewModel : ViewModelBase
    {

    }
}
(2)搜索框(MusicStoreView.axaml)

  这是一个UserControl,放在‘音乐商店对话框(MusicStoreWindow)’中,界面效果(Dark主题)如下:

 a、添加窗体

  • 在解决方案资源管理器中,右键单击 /Views 文件夹;
  • 点击 添加 Avalonia UserControl
  • 输入 名称 MusicStoreView
  • /ViewModels 文件夹添加 MusicStoreViewModel.cs,代码如下:
<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"
             xmlns:vm="using:Avalonia_MusicStore.ViewModels"
		 	 x:DataType="vm:MusicStoreViewModel"
			 mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
             x:Class="Avalonia_MusicStore.Views.MusicStoreView">
	<!--<Design.DataContext>
		<vm:MusicStoreViewModel/>
	</Design.DataContext>-->
	<DockPanel>
		<StackPanel DockPanel.Dock="Top">
			<TextBox Text="{Binding SearchText}" Watermark="搜索音乐专辑....">
				<!-- 再内部添加一个按钮  -->
				<TextBox.InnerRightContent>
					<Button  Content="搜索"  Command="{Binding SearchTextBtnCommand}"/>
				</TextBox.InnerRightContent>
				<!-- 绑定回车键  -->
				<TextBox.KeyBindings>
					<KeyBinding Gesture="Enter" Command="{Binding SearchTextBtnCommand}" />
				</TextBox.KeyBindings>
	        </TextBox>
			<ProgressBar IsVisible="{Binding IsBusy}" IsIndeterminate="True"  />
		</StackPanel>
		<Button Content="购买专辑"
				DockPanel.Dock="Bottom"
				HorizontalAlignment="Center" Command="{Binding BuyAlbumBtnCommand}" />
		<ListBox ItemsSource="{Binding SearchResults}" SelectedItem="{Binding SelectedAlbum}" Background="Transparent" Margin="0 20">
			<ListBox.ItemsPanel>
				<ItemsPanelTemplate>
					<WrapPanel />
				</ItemsPanelTemplate>
			</ListBox.ItemsPanel>
	    </ListBox>
	</DockPanel>
</UserControl>
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Album = Avalonia_MusicStore.Models.Album;

namespace Avalonia_MusicStore.ViewModels
{
    /// <summary>
    /// 音乐商店窗体ViewModel
    /// </summary>
    public partial class MusicStoreViewModel : ViewModelBase
    {
        private readonly MainWindowViewModel _MainWindowVM;
        private readonly Album _Album;

        #region 控件 Binding
        /// <summary>
        /// 购买音乐专辑 按钮展示字
        /// </summary>
        [ObservableProperty]
        private string _btnText = "购买音乐专辑";

        /// <summary>
        /// 搜索条件
        /// </summary>
        [ObservableProperty]
        private string _searchText = string.Empty;

        /// <summary>
        /// 搜索是否繁忙
        /// </summary>
        [ObservableProperty]
        private bool _isBusy = false;

        /// <summary>
        /// 被选中的专辑信息
        /// </summary>
        [ObservableProperty]
        private AlbumViewModel? _selectedAlbum;

        /// <summary>
        /// 专辑列表
        /// </summary>
        public ObservableCollection<AlbumViewModel> SearchResults { get; } = new ObservableCollection<AlbumViewModel>();
        #endregion 控件 Binding

        public MusicStoreViewModel(MainWindowViewModel mainWindowVM,Album album)
        {
            _MainWindowVM = mainWindowVM;
            _Album = album;
        }

        #region 事件Binding
        /// <summary>
        /// 搜索按钮
        /// </summary>
        [RelayCommand]
        // SearchTextEnter()
        public void SearchTextBtn()
        {
            try
            {
                Debug.WriteLine("搜索音乐专辑");
                DoSearch(SearchText);
            }
            catch (Exception ex)
            {
                string msg = ex.Message;
            }
        }

        /// <summary>
        /// 购买按钮
        /// </summary>
        [RelayCommand]
        public void BuyAlbumBtn()
        {
            try
            {
                Debug.WriteLine("购买音乐专辑");

                if (_selectedAlbum != null)
                {
                    _MainWindowVM.Albums.Add(_selectedAlbum);

                    // 保存或更新 _MainWindowVM.Albums 数据文件
                    //List<Album> albums=_MainWindowVM.Albums.Select(x=>new Album()
                    //{
                    //    Artist= x.Artist,
                    //    Title=x.Title,
                    //}).ToList();


                    //_MainWindowVM.SaveAlbums(albums);

                    // 保存 专辑封面文件
                    //_MainWindowVM.SaveAlbumPic(_selectedAlbum);
                }
            }
            catch (Exception ex)
            {
                string msg = ex.Message;
                
            }
        }
        #endregion 事件Binding

        /// <summary>
        /// 搜索音乐专辑
        /// </summary>
        /// <param name="s"></param>
        private async void DoSearch(string name)
        {
            IsBusy = true;
            SearchResults.Clear();

            if (!string.IsNullOrWhiteSpace(name))
            {
                var albums = await _Album.SearchAsync(name);

                foreach (var album in albums)
                {
                    var albumVM = new AlbumViewModel(album);
                    SearchResults.Add(albumVM);
                }
            }

            IsBusy = false;
        }
    }
}
(3)专辑搜索类(Album.cs)

  这里使用的是Neget包 iTunesSearch,主要获取专辑的标题、艺术家、封面信息;完整代码如下:

using iTunesSearch.Library;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;

namespace Avalonia_MusicStore.Models
{
    /// <summary>
    /// 专辑信息
    /// </summary>
    public class Album
    {
        #region 私有变量
        /// <summary>
        /// 提供者
        /// </summary>
        private static iTunesSearchManager s_SearchManager = new();

        /// <summary>
        /// HttpClient
        /// </summary>
        private static HttpClient s_httpClient = new();

        /// <summary>
        /// 图片缓存路径
        /// </summary>
        public string CachePath => $"./Cache/{Artist}_{Title}";
        #endregion 私有变量

        #region 公有变量
        /// <summary>
        /// 艺术家
        /// </summary>
        public string Artist { get; set; }=string.Empty;
        /// <summary>
        /// 专辑名
        /// </summary>
        public string Title { get; set; } = string.Empty;
        /// <summary>
        /// 封面链接地址
        /// </summary>
        public string CoverUrl { get; set; } = string.Empty;
        #endregion 公有变量

        /// <summary>
        /// 搜索
        /// </summary>
        /// <param name="searchTerm"></param>
        /// <returns></returns>
        public async Task<IEnumerable<Album>> SearchAsync(string searchTerm)
        {
            var query = await s_SearchManager.GetAlbumsAsync(searchTerm).ConfigureAwait(false);

            return query.Albums.Select(x =>
                new Album()
                {
                    Artist = x.ArtistName,
                    Title = x.CollectionName,  // .Replace("-","_").Replace(" ","")
                    CoverUrl = x.ArtworkUrl100.Replace("100x100bb", "600x600bb"),
                });
        }

        /// <summary>
        /// 获取图片
        /// </summary>
        /// <returns></returns>
        public async Task<Stream> LoadCoverBitmapAsync()
        {
            if (File.Exists(CachePath + ".bmp"))
            {
                return File.OpenRead(CachePath + ".bmp");
            }
            else
            {
                var data = await s_httpClient.GetByteArrayAsync(CoverUrl);
                return new MemoryStream(data);
            }
        }
    }
}
(4)专辑列表(AlbumView.axaml + ViewLocator技术

  这里使用的 视图定位器ViewLocator 技术,功能概况就是先注册一个模版(在App.axaml中注册),然后在MusicStoreView.axaml中的ListBox控件上绑定List<ViewModel>时程序会自动找到对应的View,替换ListBox控件中的模版区域(<ItemsPanelTemplate>)。

 a、App.axaml添加对 ViewLocator的引用

<Application ...
    >

    <Application.DataTemplates>
        <local:ViewLocator/>
    </Application.DataTemplates>
...

 b、AlbumView.axaml

<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"
             xmlns:vm="using:Avalonia_MusicStore.ViewModels"
		 	 x:DataType="vm:MusicStoreViewModel"
			 mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
             x:Class="Avalonia_MusicStore.Views.MusicStoreView">
	<!--<Design.DataContext>
		<vm:MusicStoreViewModel/>
	</Design.DataContext>-->
	<DockPanel>
		<StackPanel DockPanel.Dock="Top">
			<TextBox Text="{Binding SearchText}" Watermark="搜索音乐专辑....">
				<!-- 再内部添加一个按钮  -->
				<TextBox.InnerRightContent>
					<Button  Content="搜索"  Command="{Binding SearchTextBtnCommand}"/>
				</TextBox.InnerRightContent>
				<!-- 绑定回车键  -->
				<TextBox.KeyBindings>
					<KeyBinding Gesture="Enter" Command="{Binding SearchTextBtnCommand}" />
				</TextBox.KeyBindings>
	        </TextBox>
			<ProgressBar IsVisible="{Binding IsBusy}" IsIndeterminate="True"  />
		</StackPanel>
		<Button Content="购买专辑"
				DockPanel.Dock="Bottom"
				HorizontalAlignment="Center" Command="{Binding BuyAlbumBtnCommand}" />
		<ListBox ItemsSource="{Binding SearchResults}" SelectedItem="{Binding SelectedAlbum}" Background="Transparent" Margin="0 20">
			<ListBox.ItemsPanel>
				<ItemsPanelTemplate>
					<WrapPanel />
				</ItemsPanelTemplate>
			</ListBox.ItemsPanel>
	    </ListBox>
	</DockPanel>
</UserControl>

 c、AlbumViewModel.cs

using Avalonia.Media.Imaging;
using CommunityToolkit.Mvvm.ComponentModel;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Avalonia_MusicStore.ViewModels
{
    /// <summary>
    /// 专辑信息VModel
    /// </summary>
    public partial class AlbumViewModel : ViewModelBase
    {
        #region 成员
        /// <summary>
        /// 艺术家
        /// </summary>
        [ObservableProperty]
        private string artist;

        /// <summary>
        /// 专辑名
        /// </summary>
        [ObservableProperty]
        private string title;

        /// <summary>
        /// 专辑封面
        /// </summary>
        [ObservableProperty]
        private Bitmap? _cover = null;
        #endregion 成员

        public AlbumViewModel() { }
        // DI Album
        public AlbumViewModel(Models.Album album)
        {
            Artist = album.Artist;
            Title = album.Title;

            Task.Run(() =>
            {
                using (var imageStream = album.LoadCoverBitmapAsync().Result)
                {
                    Cover = Bitmap.DecodeToWidth(imageStream, 400);
                }
            });
        }
    }
}
(5)对话框返回数据

  这里对官方代码进行了修改,如上面(3)中代码所看的 MusicStoreViewModel 中的‘购买按钮’事件写法如下;即直接直接DI MainWindowViewModel,操作其中的Albums。

        private readonly MainWindowViewModel _MainWindowVM;
        private readonly Album _Album;


        public MusicStoreViewModel(MainWindowViewModel mainWindowVM,Album album)
        {
            _MainWindowVM = mainWindowVM;
            _Album = album;
        }

        /// <summary>
        /// 购买按钮
        /// </summary>
        [RelayCommand]
        public void BuyAlbumBtn()
        {
            try
            {
                Debug.WriteLine("购买音乐专辑");

                if (_selectedAlbum != null)
                {
                    _MainWindowVM.Albums.Add(_selectedAlbum);

                    // 保存或更新 _MainWindowVM.Albums 数据文件
                    //List<Album> albums=_MainWindowVM.Albums.Select(x=>new Album()
                    //{
                    //    Artist= x.Artist,
                    //    Title=x.Title,
                    //}).ToList();


                    //_MainWindowVM.SaveAlbums(albums);

                    // 保存 专辑封面文件
                    //_MainWindowVM.SaveAlbumPic(_selectedAlbum);
                }
            }
            catch (Exception ex)
            {
                string msg = ex.Message;
                
            }
        }

5、保存用户数据

  我将保存数据的逻辑放到了‘购买按钮’中,BuyAlbumBtn代码修改如下:

        /// <summary>
        /// 购买按钮
        /// </summary>
        [RelayCommand]
        public void BuyAlbumBtn()
        {
            try
            {
                Debug.WriteLine("购买音乐专辑");

                if (_selectedAlbum != null)
                {
                    _MainWindowVM.Albums.Add(_selectedAlbum);

                    // 保存或更新 _MainWindowVM.Albums 数据文件
                    List<Album> albums=_MainWindowVM.Albums.Select(x=>new Album()
                    {
                        Artist= x.Artist,
                        Title=x.Title,
                    }).ToList();


                    _MainWindowVM.SaveAlbums(albums);

                    // 保存 专辑封面文件
                    _MainWindowVM.SaveAlbumPic(_selectedAlbum);
                }
            }
            catch (Exception ex)
            {
                string msg = ex.Message;
                
            }
        }
(1)保存专辑数据(SaveAlbums)
        /// <summary>
        /// 保存专辑列表文件
        /// </summary>
        /// <param name="albumVMs">专辑列表</param>
        public void SaveAlbums(List<Album> albumVMs)
        {
            string jsonStr = JsonConvert.SerializeObject(albumVMs);

            File.WriteAllText(jsonFilePath, jsonStr,System.Text.Encoding.UTF8);
        }
(2)保存专辑封面图(SaveAlbumPic)
        /// <summary>
        /// 保存专辑封面
        /// </summary>
        /// <param name="albumVM">专辑</param>
        public void SaveAlbumPic(AlbumViewModel albumVM)
        {
            if (!Directory.Exists($"./Cache"))
            {
                Directory.CreateDirectory(dirStr);
            }

            string filePath = dirStr + $"/{albumVM.Artist}_{albumVM.Title}" + ".bmp";

            if (albumVM != null && albumVM.Cover != null)
            {
                albumVM.Cover.Save(filePath);
            }
        }

6、软件启动时加载数据

  可将加载数据的方法放到主窗体VM的构造函数中,详细代码如下:

        public MainWindowViewModel()
        {
            LoadAlbums();
        }

        /// <summary>
        /// 加载专辑数据
        /// </summary>
        public async void LoadAlbums()
        {
            try
            {
                if (File.Exists(jsonFilePath) && Directory.Exists(dirStr))
                {
                    Albums.Clear();

                    string json = File.ReadAllText(jsonFilePath);
                    List<Album> albums = JsonConvert.DeserializeObject<List<Album>>(json);

                    foreach (Album album in albums)
                    {
                        Albums.Add(new AlbumViewModel()
                        {
                            Artist = album.Artist,
                            Title = album.Title,
                            Cover = new Avalonia.Media.Imaging.Bitmap(album.CachePath + ".bmp"),
                        });
                    }
                }
            }
            catch (Exception ex)
            {

            }
        }

7、效果

二、其他案例

  其他案例见:https://github.com/AvaloniaUI/AvaloniaUI.QuickGuides

posted @ 2024-07-24 15:31  ꧁执笔小白꧂  阅读(201)  评论(0编辑  收藏  举报