当前位置:   article > 正文

Avalonia基础学习详细_avalonia 超级详细学习指南

avalonia 超级详细学习指南

以官网音乐商店为例子学习,官网地址:Avalonia Docs | Avalonia Docs

最终实现图如下:

一、创建Avalonia .NET Core MVVM App项目

模板所创建的文件和文件夹用途:

Assets包含编译到程序中的任何嵌入式资源。例如:图片、图标、字体等,UI可能需要显示的任何内容。
Models这是一个空文件夹,用于存放 MVVM 模式中的“模型”部分的代码。通常包含应用程序需要的除 UI 之外的所有内容。例如:与数据库的交互、Web API 或与硬件设备的接口。
View Models这是项目中所有视图模型的文件夹,它已经包含了一个示例。视图模型在 MVVM 模式中包含应用程序逻辑。例如:只有在用户输入了内容时按钮才可用;或者在用户点击这里时打开对话框;或者在用户输入了太大的数字时显示错误类型的逻辑。
Views这是项目中所有视图的文件夹,它已经包含了应用程序主窗口的视图。在 MVVM 模式中,视图仅包含应用程序的展示部分,即布局和表单、字体、颜色、图标和图片。在 MVVM 中,它们只有足够的代码将它们链接到视图模型层。在 Avalonia UI 中,这里只有足够管理窗口和对话框的代码。

二、窗口样式

打开文件 App.axaml,将 <Application> 元素中的 RequestedThemeVariant 属性从 Default 更改为 Dark。

  1. <Application ....
  2. RequestedThemeVariant="Dark">

RequestedThemeVariant 属性:强制覆盖全局应用程序主题变体(主题变体:可以理解为主题),就是强制控制全局主题的,具有暗色(Dark)和亮色(Light)变体。

除了全局变体以外,还可以设置特定控件的主题,使用<ThemeVariantScope RequestedThemeVariant="需要的主题">包裹控件即可。

 打开 MainWindow.axaml 文件,在<Window> 元素的结束处添加属性如下:

  1. <Window ...
  2. Title="music"
  3. //下方两行代码是添加的
  4. TransparencyLevelHint="AcrylicBlur"
  5. Background="Transparent">

TransparencyLevelHint:用于设置顶级窗口的透明度提示,有以下几个效果:

Default:默认值。
None:完全不透明。
AcrylicBlur:应用亚克力模糊效果。
Blur:应用模糊效果。

Background:设置窗口的背景颜色,Transparent是背景设置为透明。

为了将亚克力效果应用到整个窗口,在<Window>标签内添加:

  1. <window>
  2. <Panel>
  3. <ExperimentalAcrylicBorder IsHitTestVisible="False">
  4. <ExperimentalAcrylicBorder.Material>
  5. <ExperimentalAcrylicMaterial
  6. BackgroundSource="Digger"
  7. TintColor="Black"
  8. TintOpacity="1"
  9. MaterialOpacity="0.65" />
  10. </ExperimentalAcrylicBorder.Material>
  11. </ExperimentalAcrylicBorder>
  12. </Panel>
  13. </window>

<ExperimentalAcrylicBorder> 是一个用于创建具有亚克力效果的边框的控件,具有以下属性:

BackgroundSource:指定亚克力材质的背景源,可以是图像、颜色或其他资源。
TintColor:设置亚克力材质的色调颜色。
TintOpacity:定义色调颜色的不透明度。
MaterialOpacity:设置亚克力材质的整体不透明度。
IsHitTestVisible:指示边框是否响应鼠标点击事件(false为不响应)。

再次在<Window> 元素的结束处添加属性:

  1. <Window ...
  2. TransparencyLevelHint="AcrylicBlur"
  3. Background="Transparent"
  4. ExtendClientAreaToDecorationsHint="True">

ExtendClientAreaToDecorationsHint:作用是将窗口的客户端区域扩展到装饰区域,就是实现无边框窗口的效果,并且窗口的样式可以延伸到标题栏和边框的位置。

最后效果如下:

三、添加并排版控件

创建一个Styles(Avalonia)项,命名为icons。

 打开刚刚创建的icons.axaml文件,在<Styles>标签内添加样式(根据官网给的图标绘制,记住x:key所命名的值):

  1. <Style>
  2. <Style.Resources>
  3. <StreamGeometry x:Key="purchase">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>
  4. </Style.Resources>
  5. </Style>

<StreamGeometry>用于定义几何图形。

<Style> 元素用于定义样式。
<Style.Resources>定义样式资源的部分,通过将样式定义放在 <Style.Resources> 中,可以在多个控件或页面中引用这些样式。

打开App.axaml,在其中引入注册这个图标。

  1. <Application.Styles>
  2. <FluentTheme />
  3. <StyleInclude Source="avares://music/Icons.axaml" />//路径就是我们刚刚创建的icons.axaml路径
  4. </Application.Styles>

<StyleInclude>引入样式文件。

如果 Source处有错误,需要对整个项目重新生成解决方案,如果还报错,那么注意一下路径是否正确。

打开MainWindow.axaml文件,我们现在将这个图标显示在窗口中,在<Panel>标签内添加:

  1. <Panel>
  2. <ExperimentalAcrylicBorder IsHitTestVisible="False">
  3. ....
  4. </ExperimentalAcrylicBorder>
  5. <Panel Margin="40"><!--插入图标的代码-->
  6. <Button HorizontalAlignment="Right" VerticalAlignment="Top">
  7. <PathIcon Data="{StaticResource purchase}" />
  8. </Button>
  9. </Panel>
  10. </Panel>

<PathIcon> 是一个用于显示路径图形图标的控件,Data="{StaticResource purchase}" 表示从资源中获取名为 purchase 的路径数据来定义图标的形状(就是前面我们所要记住的那个x:key所命名的值)。

最终完成效果在窗口右上角将图标显示出来。 

四、按钮响应

打开MainWindowViewModel.cs文件,我们创建一个按钮的点击事件,到时候按钮中绑定的事件名是BuyMusicCommand。

  1. public class MainWindowViewModel : ViewModelBase
  2. {
  3. public ReactiveCommand<Unit, Unit> BuyMusicCommand { get; }
  4. public MainWindowViewModel()
  5. {
  6. BuyMusicCommand = ReactiveCommand.Create(RunTheThing);//当按钮点击执行
  7. void RunTheThing()
  8. {
  9. // 此处执行命令的代码。
  10. }
  11. }
  12. }

ReactiveCommand用于实现响应式命令,使用 ReactiveCommand.Create 方法创建一个 ReactiveCommand 对象,该方法接受一个异步函数作为参数,该函数将在命令执行时被调用。

接下来我们在控件中对这个点击事件进行绑定,打开MainWindow.axaml,将我们之前在页面上显示的图标按钮改一下。

  1. <Panel Margin="40">
  2. <Button HorizontalAlignment="Right" VerticalAlignment="Top"
  3. Command="{Binding BuyMusicCommand}">
  4. <PathIcon Data="{StaticResource purchase}"/>
  5. </Button>
  6. </Panel>

Command属性,该属性用于确定按钮是否被点击。绑定事件就是我们前面所定义的点击事件,他的基本语法就是{Binding 事件名},这里我们到窗口中点击该图标就会触发上面的点击事件。

五、打开另一个窗体 

我们右键Views文件夹,添加一个Avalonia Window并命名为MusicStoreWindow。

我们现在打开MusicStoreWindow.axaml文件,配置他的主题和主窗口的主题一致,这里配置也和主窗口的配置一样。

  1. <Panel>
  2. <ExperimentalAcrylicBorder IsHitTestVisible="False">
  3. <ExperimentalAcrylicBorder.Material>
  4. <ExperimentalAcrylicMaterial
  5. BackgroundSource="Digger"
  6. TintColor="Black"
  7. TintOpacity="1"
  8. MaterialOpacity="0.65" />
  9. </ExperimentalAcrylicBorder.Material>
  10. </ExperimentalAcrylicBorder>
  11. <Panel Margin="40">
  12. </Panel>
  13. </Panel>

我们再在ViewModels文件夹下创建MusicStoreViewModel和AlbumViewModel两个类。 

打开MainWindowViewModel.cs文件,我们配置点击后窗口弹出事件。

  1. public class MainWindowViewModel : ViewModelBase
  2. {
  3. //点击按钮绑定
  4. public ReactiveCommand<Unit, Unit> BuyMusicCommand { get; }
  5. //新对话框声明
  6. public Interaction<MusicStoreViewModel, AlbumViewModel?> ShowDialog { get; }
  7. public MainWindowViewModel()
  8. {
  9. BuyMusicCommand = ReactiveCommand.Create(RunTheThing);//当按钮点击执行
  10. ShowDialog = new Interaction<MusicStoreViewModel, AlbumViewModel?>();
  11. async void RunTheThing()
  12. {
  13. var store = new MusicStoreViewModel();
  14. var result = await ShowDialog.Handle(store);
  15. }
  16. }
  17. }

 我们打开MainWindow.axaml.cs文件,我们将继承至window修改为继承至ReactiveWindow<MainWindowViewModel>。

  1. public partial class MainWindow : ReactiveWindow<MainWindowViewModel>
  2. {
  3. public MainWindow()
  4. {
  5. InitializeComponent();
  6. this.WhenActivated(action =>
  7. action(ViewModel!.ShowDialog.RegisterHandler(DoShowDialogAsync)));
  8. }
  9. private async Task DoShowDialogAsync(InteractionContext<MusicStoreViewModel,
  10. AlbumViewModel?> interaction)
  11. {
  12. var dialog = new MusicStoreWindow();
  13. dialog.DataContext = interaction.Input;
  14. var result = await dialog.ShowDialog<AlbumViewModel?>(this);
  15. interaction.SetOutput(result);
  16. }
  17. }

WhenActivated用于在视图模型被激活时执行一些操作,提供一个回调函数。

ViewModel的值取决于ReactiveWindow<MainWindowViewModel>的泛值,也就是MainWindowViewModel这个对象。

RegisterHandler用于执行一些计时操作,例如显示对话框和等待用户的响应。

 六、添加对话框

在Views文件夹下创建一个User Control项目名为MusicStoreViews。

打开该文件,添加如下代码

  1. <DockPanel>
  2. <StackPanel DockPanel.Dock="Top"><!--停靠最顶部-->
  3. <TextBox Watermark="输入要查找的..." />
  4. <ProgressBar IsIndeterminate="True" />
  5. </StackPanel>
  6. <Button Content="Buy Album"
  7. DockPanel.Dock="Bottom"
  8. HorizontalAlignment="Center" />
  9. <ListBox/>
  10. </DockPanel>

 <DockPanel>用于控制子元素在面板内的停靠位置,它具有 Dock 属性,子元素可以通过设置这个属性来指定停靠的方向,例如 Left、Right、Top、Bottom。

<ProgressBar> 是用于展示进度的控件,Value 表示当前进度值,Minimum 表示进度的最小值,Maximum 表示进度的最大值,下面代码表50% 的进度,IsIndeterminate为Ture进度条会显示为一个持续移动的视觉效果。

<ProgressBar Value="50" Minimum="0" Maximum="100" />

打开MusicStoreWindow.axaml文件。

  1. <Window ...
  2. xmlns:views="using:music.Views" >
  3. <Panel Margin="40">
  4. <views:MusicStoreViews/>
  5. </Panel>

使用这种方式可以将控件以模块化的形式展示在窗口当中:

xmlns:views="using:music.Views"相当于进行注册,对music下的views文件当中的所有控件进行注册,后面我们再使用的时候直接以命名空间前缀来引用视图。

XAML 文件的其他位置,可以使用添加的命名空间前缀来引用视图,<views:MusicStoreViews/>MusicStoreViews就是我们上面所创建的那个控件的命名空间。 

最终完成效果如下(如同vue的组件化开发一样):

七、 视图添加

打开MusicStoreViewModel文件,使其继承至ViewModelBase。

  1. public class MusicStoreViewModel : ViewModelBase
  2. {
  3. private string? _searchText;//搜索内容
  4. private bool _isBusy;//控制进度条是否显示
  5. private AlbumViewModel? _selectedAlbum;//选择的内容
  6. public ObservableCollection<AlbumViewModel> SearchResults { get; } = new();//数据源
  7. public MusicStoreViewModel()
  8. {
  9. //添加模拟数据
  10. SearchResults.Add(new AlbumViewModel());
  11. SearchResults.Add(new AlbumViewModel());
  12. SearchResults.Add(new AlbumViewModel());
  13. }
  14. public AlbumViewModel? SelectedAlbum
  15. {
  16. get => _selectedAlbum;
  17. set => this.RaiseAndSetIfChanged(ref _selectedAlbum, value);
  18. }
  19. public string? SearchText
  20. {
  21. get => _searchText;
  22. set => this.RaiseAndSetIfChanged(ref _searchText, value);
  23. }
  24. public bool IsBusy
  25. {
  26. get => _isBusy;
  27. set => this.RaiseAndSetIfChanged(ref _isBusy, value);
  28. }
  29. }

ObservableCollection实现了 INotifyCollectionChanged 接口,当集合中的元素被添加、删除或整个集合被刷新时,它能够自动通知绑定的控件进行相应的更新

打开MusicStoreViews.axaml文件, 将其修改为:

  1. <DockPanel>
  2. <StackPanel DockPanel.Dock="Top">
  3. <TextBox Text="{Binding SearchText}" Watermark="输入要查找的..." />
  4. <ProgressBar IsIndeterminate="True" IsVisible="{Binding IsBusy}" />
  5. </StackPanel>
  6. <Button Content="Buy Album"
  7. DockPanel.Dock="Bottom"
  8. HorizontalAlignment="Center" />
  9. <ListBox ItemsSource="{Binding SearchResults}" SelectedItem="{Binding SelectedAlbum}"
  10. Background="Transparent" Margin="0 20">
  11. <ListBox.ItemsPanel>
  12. <ItemsPanelTemplate>
  13. <WrapPanel />
  14. </ItemsPanelTemplate>
  15. </ListBox.ItemsPanel>
  16. </ListBox>
  17. </DockPanel>

Text输入内容,绑定我们的_searchText数据。

IsVisible控制进度条是否可见,true为可见,绑定我们的_isBusy的数据。

ItemsSource用于绑定一个数据源,以显示其中的项,绑定我们的SearchResults 的数据。

SelectedItem用于获取当前选中的项,选中的内容会存放到_selectedAlbum的数据中。

<ListBox.ItemsPanel>用于指定 <ListBox> 内部如何排列,<WrapPanel> 会使列表项在一行排满后,自动换行到下一行继续排列,以实现项的自动换行布局效果。

打开Icons.axaml文件,添加一个“音符”图标的资源。您将使用这个图标作为应用程序中专辑封面的占位符图标,它们最终将被下载的专辑封面艺术品替换,记住我们这里的x:key的命名。 

  1. <Style>
  2. <Style.Resources>
  3. <StreamGeometry x:Key="music_regular">M11.5,2.75 C11.5,2.22634895 12.0230228,1.86388952 12.5133347,2.04775015 L18.8913911,4.43943933 C20.1598961,4.91511241 21.0002742,6.1277638 21.0002742,7.48252202 L21.0002742,10.7513533 C21.0002742,11.2750044 20.4772513,11.6374638 19.9869395,11.4536032 L13,8.83332147 L13,17.5 C13,17.5545945 12.9941667,17.6078265 12.9830895,17.6591069 C12.9940859,17.7709636 13,17.884807 13,18 C13,20.2596863 10.7242052,22 8,22 C5.27579485,22 3,20.2596863 3,18 C3,15.7403137 5.27579485,14 8,14 C9.3521238,14 10.5937815,14.428727 11.5015337,15.1368931 L11.5,2.75 Z M8,15.5 C6.02978478,15.5 4.5,16.6698354 4.5,18 C4.5,19.3301646 6.02978478,20.5 8,20.5 C9.97021522,20.5 11.5,19.3301646 11.5,18 C11.5,16.6698354 9.97021522,15.5 8,15.5 Z M13,3.83223733 L13,7.23159672 L19.5002742,9.669116 L19.5002742,7.48252202 C19.5002742,6.75303682 19.0477629,6.10007069 18.3647217,5.84393903 L13,3.83223733 Z</StreamGeometry>
  4. </Style.Resources>
  5. </Style>

在Views文件夹下添加一个User Control类型的文件,命名为AlbumView,并且打开他:

  1. <StackPanel Spacing="5" Width="200">
  2. <Border CornerRadius="10" ClipToBounds="True">
  3. <Panel Background="#7FFF22DD">
  4. <Image Width="200" Stretch="Uniform" />
  5. <Panel Height="200">
  6. <PathIcon Height="75" Width="75" Data="{StaticResource music_regular}" />
  7. </Panel>
  8. </Panel>
  9. </Border>
  10. </StackPanel>

Data绑定的静态资源,也就是上面我们所创建的一个图标。

打开AlbumViewModel文件夹,使其继承至ViewModelBase。

public class AlbumViewModel : ViewModelBase

因为我们之前在MusicStoreViewModel 文件当中SearchResults的数据源中添加了3个AlbumViewModel视图,ListBox也绑定了SearchResults作为数据源,那么在页面上就会显示出这三个图标。

AlbumView.axaml和AlbumViewModel.cs之间能绑定是因为具有相同的基本名称 “Album”,并且我们可以用x:DataType进行绑定。

最终效果如下: 

 

 八、数据展示

后面基本都是逻辑代码,建议结合官网的介绍进行查看,部分解释在代码当中。

安装NuGet包:NuGet\Install-Package iTunesSearch -Version 1.0.44

在Models文件夹下新建一个类名Album,进入其中添加代码:

  1. private static iTunesSearchManager s_SearchManager = new();
  2. private static HttpClient s_httpClient = new();
  3. private string CachePath => $"./Cache/{Artist} - {Title}";
  4. public string Artist { get; set; }//存放歌手
  5. public string Title { get; set; }//存放专辑名
  6. public string CoverUrl { get; set; }//存放专辑图
  7. public Album(string artist, string title, string coverUrl)
  8. {
  9. Artist = artist;
  10. Title = title;
  11. CoverUrl = coverUrl;
  12. }
  13. public static async Task<IEnumerable<Album>> SearchAsync(string searchTerm)
  14. {
  15. //根据传入值searchTerm获取所有相关专辑信息,ConfigureAwait(false)等待异步操作完成
  16. var query = await s_SearchManager.GetAlbumsAsync(searchTerm)
  17. .ConfigureAwait(false);
  18. //根据获取到的专辑信息返回歌手名,专辑名,以及专辑图(路径中的"100x100bb"替换为"600x600bb")
  19. return query.Albums.Select(x =>
  20. new Album(x.ArtistName, x.CollectionName,
  21. x.ArtworkUrl100.Replace("100x100bb", "600x600bb")));
  22. }
  23. public async Task<Stream> LoadCoverBitmapAsync()
  24. {
  25. //查看文件是否存在
  26. if (File.Exists(CachePath + ".bmp"))
  27. {
  28. //存在,打开文件返回该文件的流
  29. return File.OpenRead(CachePath + ".bmp");
  30. }
  31. else
  32. {
  33. //不存在,则发送向CoverUrl发送http请求
  34. var data = await s_httpClient.GetByteArrayAsync(CoverUrl);
  35. //返回一个转换的流
  36. return new MemoryStream(data);
  37. }
  38. }

打开AlbumViewModel文件夹,添加并修改代码:

  1. public class AlbumViewModel : ViewModelBase
  2. {
  3. private readonly Album _album;
  4. private Bitmap? _cover;
  5. public AlbumViewModel(Album album)
  6. {
  7. _album = album;
  8. }
  9. public Bitmap? Cover
  10. {
  11. get => _cover;
  12. private set => this.RaiseAndSetIfChanged(ref _cover, value);
  13. }
  14. public async Task LoadCover()
  15. {
  16. //获取返回的文件流
  17. await using (var imageStream = await _album.LoadCoverBitmapAsync())
  18. {
  19. //多线程解码文件流中的数据并将图片宽度设置为400
  20. Cover = await Task.Run(() => Bitmap.DecodeToWidth(imageStream, 400));
  21. }
  22. }
  23. public string Artist => _album.Artist;
  24. public string Title => _album.Title;
  25. }

 打开MusicStoreViewModel文件夹,修改并保存代码:

  1. public class MusicStoreViewModel : ViewModelBase
  2. {
  3. private string? _searchText;//搜索内容
  4. private bool _isBusy;//控制进度条是否显示
  5. private AlbumViewModel? _selectedAlbum;//选择的内容
  6. private CancellationTokenSource? _cancellationTokenSource;
  7. public ObservableCollection<AlbumViewModel> SearchResults { get; } = new();//数据源
  8. private async void LoadCovers(CancellationToken cancellationToken)
  9. {
  10. foreach (var album in SearchResults.ToList())
  11. {
  12. await album.LoadCover();
  13. if (cancellationToken.IsCancellationRequested)
  14. {
  15. return;
  16. }
  17. }
  18. }
  19. public MusicStoreViewModel()
  20. {
  21. //当SearchText发生变化且400毫秒内没有变化时触发DoSearch方法
  22. this.WhenAnyValue(x => x.SearchText)
  23. .Throttle(TimeSpan.FromMilliseconds(400))
  24. .ObserveOn(RxApp.MainThreadScheduler)
  25. .Subscribe(DoSearch!);
  26. }
  27. private async void DoSearch(string s)
  28. {
  29. //使进度条可见
  30. IsBusy = true;
  31. //清空SearchResults
  32. SearchResults.Clear();
  33. _cancellationTokenSource?.Cancel();
  34. _cancellationTokenSource = new CancellationTokenSource();
  35. var cancellationToken = _cancellationTokenSource.Token;
  36. //判断传入值s是否为空
  37. if (!string.IsNullOrWhiteSpace(s))
  38. {
  39. //获取到返回的专辑信息,返回的使IEnumerable<Album>类型
  40. var albums = await Album.SearchAsync(s);
  41. //得到每一个Album数据并且添加到数据源当中
  42. foreach (var album in albums)
  43. {
  44. var vm = new AlbumViewModel(album);
  45. SearchResults.Add(vm);
  46. }
  47. if (!cancellationToken.IsCancellationRequested)
  48. {
  49. LoadCovers(cancellationToken);
  50. }
  51. }
  52. //进度条不可见
  53. IsBusy = false;
  54. }
  55. public AlbumViewModel? SelectedAlbum
  56. {
  57. get => _selectedAlbum;
  58. set => this.RaiseAndSetIfChanged(ref _selectedAlbum, value);
  59. }
  60. public string? SearchText
  61. {
  62. get => _searchText;
  63. set => this.RaiseAndSetIfChanged(ref _searchText, value);
  64. }
  65. public bool IsBusy
  66. {
  67. get => _isBusy;
  68. set => this.RaiseAndSetIfChanged(ref _isBusy, value);
  69. }
  70. }

进入AlbumView.axaml文件当中,添加末尾两个文本:

  1. <StackPanel Spacing="5" Width="200">
  2. <Border CornerRadius="10" ClipToBounds="True">
  3. <Panel Background="#7FFF22DD">
  4. <Image Width="200" Stretch="Uniform" Source="{Binding Cover}" />
  5. <Panel Height="200" IsVisible="{Binding Cover, Converter={x:Static ObjectConverters.IsNull}}">
  6. <PathIcon Height="75" Width="75" Data="{StaticResource music_regular}" />
  7. </Panel>
  8. </Panel>
  9. </Border>
  10. <TextBlock HorizontalAlignment="Center" Text="{Binding Title}"/>
  11. <TextBlock HorizontalAlignment="Center" Text="{Binding Artist}"/>
  12. </StackPanel>

进入MusicStoreViews.axaml文件夹当中:

  1. <DockPanel>
  2. <StackPanel DockPanel.Dock="Top">
  3. <TextBox Text="{Binding SearchText}" Watermark="输入要查找的..." />
  4. <ProgressBar IsIndeterminate="True" IsVisible="{Binding IsBusy}" />
  5. </StackPanel>
  6. <Button Content="Buy Album"
  7. DockPanel.Dock="Bottom"
  8. HorizontalAlignment="Center" />
  9. <ListBox ItemsSource="{Binding SearchResults}" SelectedItem="{Binding SelectedAlbum}"
  10. Background="Transparent" Margin="0 20">
  11. <ListBox.ItemsPanel>
  12. <ItemsPanelTemplate>
  13. <WrapPanel />
  14. </ItemsPanelTemplate>
  15. </ListBox.ItemsPanel>
  16. </ListBox>
  17. </DockPanel>

 进入MusicStoreWindow.axaml文件夹:

  1. <Panel>
  2. <ExperimentalAcrylicBorder IsHitTestVisible="False">
  3. <ExperimentalAcrylicBorder.Material>
  4. <ExperimentalAcrylicMaterial
  5. BackgroundSource="Digger"
  6. TintColor="Black"
  7. TintOpacity="1"
  8. MaterialOpacity="0.65" />
  9. </ExperimentalAcrylicBorder.Material>
  10. </ExperimentalAcrylicBorder>
  11. <Panel Margin="40">
  12. <views:MusicStoreViews/>
  13. </Panel>
  14. </Panel>
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/代码探险家/article/detail/889308
推荐阅读
相关标签
  

闽ICP备14008679号