专辑服务
在这一页中,您将为应用程序添加一些业务逻辑。这将允许您替换模拟数据,并从搜索中获取一些真实的专辑数据。这个业务逻辑代码形成了 MVVM 模式中的“模型”部分。
为了在应用程序中实现真实的专辑搜索,您将使用一个可以调用 Apple iTunes Web API 专辑搜索的 NuGet 包。
Apple Web API 包
按照以下步骤添加所需的 NuGet 包:
- 如果应用程序仍在运行,请停止应用程序。
- 右键单击项目。
- 单击 管理 NuGet 软件包。
- 在左上角的搜索框中键入 “itunes”。
- 单击 iTunesSearch,然后单击 安装。
MVVM 模型
在本教程中,应用程序很简单,您可以在同一个类中实现 MVVM 模式的“模型”部分所需的业务服务。这个类将包含专辑的数据模型和搜索所需的方法。
按照以下步骤添加专辑业务逻辑:
- 在解决方案资源管理器中,右键单击 /Models 文件夹,然后单击 添加。
- 单击 类。
- 在提示输入名称时,键入 “Album”。
- 添加以下代码:
using iTunesSearch.Library;
using System.Collections.Generic;
using System.Linq;
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 Task<IEnumerable<Album>> 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")));
}
}
}
专辑视图模型
为了在搜索结果列表中显示来自 Web API 的每个专辑(数据模型)的数据,您将创建一个专辑视图模型,并将其绑定到专辑视图(磁贴)以进行显示。
您的专辑视图模型目前是空的。它需要能够存储来自搜索的专辑数据,并具有一些用于艺术家名称和专辑标题的属性。然后,这些属性将绑定到视图以进行显示。
在这一步中,您将使用视图模型和(业务逻辑)模型之间的依赖关系的常见模式。这是指视图模型包含数据模型的一个实例,然后根据需要公开其某些属性以进行显示。
按照以下步骤准备专辑视图模型:
- 定位并打开 AlbumViewModel.cs 文件。
- 添加如下所示的代码:
private readonly Album _album;
public AlbumViewModel(Album album)
{
_album = album;
}
public string Artist => _album.Artist;
public string Title => _album.Title;
请注意,由于视图模型属性在运行时不会在 UI 中更改,因此它们没有 setter,只有一个普通的 getter,这里也不需要使用 RaiseAndSetIfChanged
方法。
开始搜索
在这一步中,您将向音乐商店视图模型中添加一些代码,以便每当搜索文本发生更改时,专辑模型(业务服务)上的 SearchAsync
方法就会启动。当它完成时,搜索将其结果放入可观察集合 SearchResults
中。这个集合已经绑定到列表框,因此通过对专辑视图进行小调整,搜索结果将显示为您之前准备的磁贴。
按照以下步骤,在搜索文本更改时启动搜索:
- 定位并打开 MusicStoreViewModel.cs 文件。
- 替换构造函数代码,并添加额外的代码,如下所示:
using Avalonia.MusicStore.Models;
using ReactiveUI;
using System;
using System.Collections.ObjectModel;
using System.Reactive.Linq;
using System.Threading;
namespace Avalonia.MusicStore.ViewModels
{
public class MusicStoreViewModel : ViewModelBase
{
...
public MusicStoreViewModel()
{
this.WhenAnyValue(x => x.SearchText)
.Throttle(TimeSpan.FromMilliseconds(400))
.ObserveOn(RxApp.MainThreadScheduler)
.Subscribe(DoSearch!);
}
private async void DoSearch(string s)
{
IsBusy = true;
SearchResults.Clear();
if (!string.IsNullOrWhiteSpace(s))
{
var albums = await Album.SearchAsync(s);
foreach (var album in albums)
{
var vm = new AlbumViewModel(album);
SearchResults.Add(vm);
}
}
IsBusy = false;
}
}
}
WhenAnyValue
方法由 ReactiveUI 框架提供,作为 ReactiveObject
的一部分(继承自 ViewModelBase
)。该方法接受一个 lambda 表达式参数,该参数获取要观察的属性。因此,在上面的代码中,每当用户键入以更改搜索文本时,都会发生一个事件。
在尝试运行搜索之前等待用户停止键入是一个很好的设计。Throttle
方法可以让事件在经过指定的时间间隔(400毫秒)后没有再次发生才会被处理。这意味着在用户停止键入 400 毫秒或更长时间之前,不会开始处理。
ObserveOn
方法是必需的,以确保订阅的方法始终在 UI 线程上调用。在 Avalonia UI 应用程序中,您必须始终在 UI 线程上更新 UI。
最后,Subscribe
方法对每个观察到的事件调用 DoSearch
方法。DoSearch
方法以异步方式运行,没有返回值。