网站报错 自动404,程序员培训班课程,网站开发公司内部数据字典,网站开发png图标素材目录
一 简介
二 设计思路
三 源码 一 简介
支持在线检索音乐#xff0c;支持实时浏览当前收藏的音乐及音乐数据的持久化。 二 设计思路
采用MVVM架构#xff0c;前后端分离#xff0c;子界面弹出始终位于主界面的中心。 三 源码 视窗引导启动源码#xff1a;
namesp…
目录
一 简介
二 设计思路
三 源码 一 简介
支持在线检索音乐支持实时浏览当前收藏的音乐及音乐数据的持久化。 二 设计思路
采用MVVM架构前后端分离子界面弹出始终位于主界面的中心。 三 源码 视窗引导启动源码
namespace Avalonia.MusicStore
{public class ViewLocator : IDataTemplate{public Control? Build(object? data){if (data is null)return null;var name data.GetType().FullName!.Replace(ViewModel, View, StringComparison.Ordinal);var type Type.GetType(name);if (type ! null){var control (Control)Activator.CreateInstance(type)!;control.DataContext data;return control;}return new TextBlock { Text Not Found: name };}public bool Match(object? data){return data is ViewModelBase;}}
}using Avalonia;
using Avalonia.ReactiveUI;
using System;namespace Avalonia.MusicStore
{internal sealed class Program{// Initialization code. Dont use any Avalonia, third-party APIs or any// SynchronizationContext-reliant code before AppMain is called: things arent initialized// yet and stuff might break.[STAThread]public static void Main(string[] args) BuildAvaloniaApp().StartWithClassicDesktopLifetime(args);// Avalonia configuration, dont remove; also used by visual designer.public static AppBuilder BuildAvaloniaApp() AppBuilder.ConfigureApp().UsePlatformDetect().WithInterFont().LogToTrace().UseReactiveUI();}
}模型源码
using iTunesSearch.Library;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Text.Json;
using System.Threading.Tasks;namespace Avalonia.MusicStore.Models
{public class Album{private static iTunesSearchManager s_SearchManager new();public string Artist { get; set; }public string Title { get; set; }public string CoverUrl { get; set; }public Album(string artist, string title, string coverUrl){Artist artist;Title title;CoverUrl coverUrl;}public static async TaskIEnumerableAlbum SearchAsync(string searchTerm){var query await s_SearchManager.GetAlbumsAsync(searchTerm).ConfigureAwait(false);return query.Albums.Select(x new Album(x.ArtistName, x.CollectionName,x.ArtworkUrl100.Replace(100x100bb, 600x600bb)));}private static HttpClient s_httpClient new();private string CachePath $./Cache/{Artist} - {Title};public async TaskStream LoadCoverBitmapAsync(){if (File.Exists(CachePath .bmp)){return File.OpenRead(CachePath .bmp);}else{var data await s_httpClient.GetByteArrayAsync(CoverUrl);return new MemoryStream(data);}}public async Task SaveAsync(){if (!Directory.Exists(./Cache)){Directory.CreateDirectory(./Cache);}using (var fs File.OpenWrite(CachePath)){await SaveToStreamAsync(this, fs);}}public Stream SaveCoverBitmapStream(){return File.OpenWrite(CachePath .bmp);}private static async Task SaveToStreamAsync(Album data, Stream stream){await JsonSerializer.SerializeAsync(stream, data).ConfigureAwait(false);}public static async TaskAlbum LoadFromStream(Stream stream){return (await JsonSerializer.DeserializeAsyncAlbum(stream).ConfigureAwait(false))!;}public static async TaskIEnumerableAlbum LoadCachedAsync(){if (!Directory.Exists(./Cache)){Directory.CreateDirectory(./Cache);}var results new ListAlbum();foreach (var file in Directory.EnumerateFiles(./Cache)){if (!string.IsNullOrWhiteSpace(new DirectoryInfo(file).Extension)) continue;await using var fs File.OpenRead(file);results.Add(await Album.LoadFromStream(fs).ConfigureAwait(false));}return results;}}
}模型视图源码
using Avalonia.Media.Imaging;
using Avalonia.MusicStore.Models;
using ReactiveUI;
using System.Threading.Tasks;namespace Avalonia.MusicStore.ViewModels
{public class AlbumViewModel : ViewModelBase{private readonly Album _album;public AlbumViewModel(Album album){_album album;}public string Artist _album.Artist;public string Title _album.Title;private Bitmap? _cover;public Bitmap? Cover{get _cover;private set this.RaiseAndSetIfChanged(ref _cover, value);}public async Task LoadCover(){await using (var imageStream await _album.LoadCoverBitmapAsync()){Cover await Task.Run(() Bitmap.DecodeToWidth(imageStream, 400));}}public async Task SaveToDiskAsync(){await _album.SaveAsync();if (Cover ! null){var bitmap Cover;await Task.Run(() {using (var fs _album.SaveCoverBitmapStream()){bitmap.Save(fs);}});}}}
}using Avalonia.MusicStore.Models;
using ReactiveUI;
using System.Collections.ObjectModel;
using System.Linq;
using System.Reactive.Concurrency;
using System.Reactive.Linq;
using System.Windows.Input;namespace Avalonia.MusicStore.ViewModels
{public class MainWindowViewModel : ViewModelBase{public ICommand BuyMusicCommand { get; }public InteractionMusicStoreViewModel, AlbumViewModel? ShowDialog { get; }public ObservableCollectionAlbumViewModel Albums { get; } new();public MainWindowViewModel(){ShowDialog new InteractionMusicStoreViewModel, AlbumViewModel?();BuyMusicCommand ReactiveCommand.CreateFromTask(async () {var store new MusicStoreViewModel();var result await ShowDialog.Handle(store);if (result ! null){Albums.Add(result);await result.SaveToDiskAsync();}});RxApp.MainThreadScheduler.Schedule(LoadAlbums);}private async void LoadAlbums(){var albums (await Album.LoadCachedAsync()).Select(x new AlbumViewModel(x));foreach (var album in albums){Albums.Add(album);}foreach (var album in Albums.ToList()){await album.LoadCover();}}}
}using Avalonia.MusicStore.Models;
using ReactiveUI;
using System;
using System.Collections.ObjectModel;
using System.Linq;
using System.Reactive;
using System.Reactive.Linq;
using System.Threading;namespace Avalonia.MusicStore.ViewModels
{public class MusicStoreViewModel : ViewModelBase{private string? _searchText;private bool _isBusy;public string? SearchText{get _searchText;set this.RaiseAndSetIfChanged(ref _searchText, value);}public bool IsBusy{get _isBusy;set this.RaiseAndSetIfChanged(ref _isBusy, value);}private AlbumViewModel? _selectedAlbum;public ObservableCollectionAlbumViewModel SearchResults { get; } new();public AlbumViewModel? SelectedAlbum{get _selectedAlbum;set this.RaiseAndSetIfChanged(ref _selectedAlbum, value);}public MusicStoreViewModel(){this.WhenAnyValue(x x.SearchText).Throttle(TimeSpan.FromMilliseconds(400)).ObserveOn(RxApp.MainThreadScheduler).Subscribe(DoSearch!);BuyMusicCommand ReactiveCommand.Create(() {return SelectedAlbum;});}private async void DoSearch(string s){IsBusy true;SearchResults.Clear();_cancellationTokenSource?.Cancel();_cancellationTokenSource new CancellationTokenSource();var cancellationToken _cancellationTokenSource.Token;if (!string.IsNullOrWhiteSpace(s)){var albums await Album.SearchAsync(s);foreach (var album in albums){var vm new AlbumViewModel(album);SearchResults.Add(vm);}if (!cancellationToken.IsCancellationRequested){LoadCovers(cancellationToken);}}IsBusy false;}private async void LoadCovers(CancellationToken cancellationToken){foreach (var album in SearchResults.ToList()){await album.LoadCover();if (cancellationToken.IsCancellationRequested){return;}}}private CancellationTokenSource? _cancellationTokenSource;public ReactiveCommandUnit, AlbumViewModel? BuyMusicCommand { get; }}
}using ReactiveUI;namespace Avalonia.MusicStore.ViewModels
{public class ViewModelBase : ReactiveObject{}
}视图源码
UserControlx:ClassAvalonia.MusicStore.Views.AlbumViewxmlnshttps://github.com/avaloniauixmlns:xhttp://schemas.microsoft.com/winfx/2006/xamlxmlns:dhttp://schemas.microsoft.com/expression/blend/2008xmlns:mchttp://schemas.openxmlformats.org/markup-compatibility/2006xmlns:vmusing:Avalonia.MusicStore.ViewModelsWidth200d:DesignHeight450d:DesignWidth800x:DataTypevm:AlbumViewModelmc:IgnorabledStackPanel Width200 Spacing5Border ClipToBoundsTrue CornerRadius10Panel Background#7FFF22DDImageWidth200Source{Binding Cover}StretchUniform /Panel Height200 IsVisible{Binding Cover, Converter{x:Static ObjectConverters.IsNull}}PathIconWidth75Height75Data{StaticResource music_regular} //Panel/Panel/BorderTextBlock HorizontalAlignmentCenter Text{Binding Title} /TextBlock HorizontalAlignmentCenter Text{Binding Artist} //StackPanel
/UserControlWindowx:ClassAvalonia.MusicStore.Views.MainWindowxmlnshttps://github.com/avaloniauixmlns:xhttp://schemas.microsoft.com/winfx/2006/xamlxmlns:dhttp://schemas.microsoft.com/expression/blend/2008xmlns:mchttp://schemas.openxmlformats.org/markup-compatibility/2006xmlns:viewsclr-namespace:Avalonia.MusicStore.Viewsxmlns:vmusing:Avalonia.MusicStore.ViewModelsTitleAvalonia.MusicStored:DesignHeight450d:DesignWidth800x:DataTypevm:MainWindowViewModelBackgroundTransparentExtendClientAreaToDecorationsHintTrueIcon/Assets/avalonia-logo.icoTransparencyLevelHintAcrylicBlurWindowStartupLocationCenterScreenmc:IgnorabledPanelExperimentalAcrylicBorder IsHitTestVisibleFalseExperimentalAcrylicBorder.MaterialExperimentalAcrylicMaterialBackgroundSourceDiggerMaterialOpacity0.65TintColorBlackTintOpacity1 //ExperimentalAcrylicBorder.Material/ExperimentalAcrylicBorderPanel Margin40ButtonHorizontalAlignmentRightVerticalAlignmentTopCommand{Binding BuyMusicCommand}PathIcon Data{StaticResource store_microsoft_regular} //ButtonItemsControl Margin0,40,0,0 ItemsSource{Binding Albums}ItemsControl.ItemsPanelItemsPanelTemplateWrapPanel //ItemsPanelTemplate/ItemsControl.ItemsPanelItemsControl.ItemTemplateDataTemplateviews:AlbumView Margin0,0,20,20 //DataTemplate/ItemsControl.ItemTemplate/ItemsControl/Panel/Panel/Windowusing Avalonia.MusicStore.ViewModels;
using Avalonia.ReactiveUI;
using ReactiveUI;
using System.Threading.Tasks;namespace Avalonia.MusicStore.Views
{public partial class MainWindow : ReactiveWindowMainWindowViewModel{public MainWindow(){InitializeComponent();this.WhenActivated(action action(ViewModel!.ShowDialog.RegisterHandler(DoShowDialogAsync)));}private async Task DoShowDialogAsync(InteractionContextMusicStoreViewModel,AlbumViewModel? interaction){var dialog new MusicStoreWindow();dialog.DataContext interaction.Input;var result await dialog.ShowDialogAlbumViewModel?(this);interaction.SetOutput(result);}}
}
UserControlx:ClassAvalonia.MusicStore.Views.MusicStoreViewxmlnshttps://github.com/avaloniauixmlns:xhttp://schemas.microsoft.com/winfx/2006/xamlxmlns:dhttp://schemas.microsoft.com/expression/blend/2008xmlns:mchttp://schemas.openxmlformats.org/markup-compatibility/2006xmlns:vmusing:Avalonia.MusicStore.ViewModelsd:DesignHeight450d:DesignWidth800x:DataTypevm:MusicStoreViewModelmc:IgnorabledDockPanelStackPanel DockPanel.DockTopTextBox Text{Binding SearchText} WatermarkSearch for Albums.... /ProgressBar IsIndeterminateTrue IsVisible{Binding IsBusy} //StackPanelButtonHorizontalAlignmentCenterCommand{Binding BuyMusicCommand}ContentBuy AlbumDockPanel.DockBottom /ListBoxMargin0,20BackgroundTransparentItemsSource{Binding SearchResults}SelectedItem{Binding SelectedAlbum}ListBox.ItemsPanelItemsPanelTemplateWrapPanel //ItemsPanelTemplate/ListBox.ItemsPanel/ListBox/DockPanel
/UserControlWindowx:ClassAvalonia.MusicStore.Views.MusicStoreWindowxmlnshttps://github.com/avaloniauixmlns:xhttp://schemas.microsoft.com/winfx/2006/xamlxmlns:dhttp://schemas.microsoft.com/expression/blend/2008xmlns:mchttp://schemas.openxmlformats.org/markup-compatibility/2006xmlns:viewsusing:Avalonia.MusicStore.ViewsTitleMusicStoreWindowWidth1000Height550ExtendClientAreaToDecorationsHintTrueTransparencyLevelHintAcrylicBlurWindowStartupLocationCenterOwnermc:IgnorabledPanelExperimentalAcrylicBorder IsHitTestVisibleFalseExperimentalAcrylicBorder.MaterialExperimentalAcrylicMaterialBackgroundSourceDiggerMaterialOpacity0.65TintColorBlackTintOpacity1 //ExperimentalAcrylicBorder.Material/ExperimentalAcrylicBorderPanel Margin40views:MusicStoreView //Panel/Panel
/Windowusing Avalonia.MusicStore.ViewModels;
using Avalonia.ReactiveUI;
using ReactiveUI;
using System;namespace Avalonia.MusicStore.Views
{public partial class MusicStoreWindow : ReactiveWindowMusicStoreViewModel{public MusicStoreWindow(){InitializeComponent();this.WhenActivated(action action(ViewModel!.BuyMusicCommand.Subscribe(Close)));}}
}