欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 科技 > 能源 > Avalonia创建导航菜单

Avalonia创建导航菜单

2025/4/19 16:21:41 来源:https://blog.csdn.net/cun_king/article/details/140397659  浏览:    关键词:Avalonia创建导航菜单

1. 简介

已开源,后续还会继续更新学习到的内容,欢迎Star,GitHub地址

开发Avalonia需要的一些资料,我已经分享到另一篇文章

示意图

image-20240713003942667

涉及到内容:

  • MVVM
  • 路由
  • 模板

开发:

  • 开发工具:Rider,下载插件AvaloniaRider
  • .NET版本:8
  • Avalonia版本:11.0.10

image-20240712233519470

2.主要内容

2.1 创建

但是我好像不清楚如何使用Rider创建一个Avalonia项目,万能的网友有人指点一二吗?

我先用VS2022创建一个Avalonia的MVVM项目(如何创建请参考这篇文章链接),然后再使用Rider打开。

2.2 布局

先使用Grid切出两列。关于Grid,可以把它认为是表格布局,切分出几行几列,就可以在对应的单元格里放一些控件。

<Grid ColumnDefinitions="160,*">
</Grid>

这个相对于WPF来说是一个简写,意思是切分出两列,一列宽度为160,剩下的一列填充整个空间,这里的*是比例,如果按下面的写法,是按照1:2的比例切分空间。

<Grid ColumnDefinitions="*,2*">
</Grid>

2.3 MVVM

具体的MVVM可以在网上查找,很多资料,我就不赘述了。简单来说,A控件绑定一个数据,那么要修改A控件的显示内容的话,只需要修改这个数据,A控件就自动更新了,取代了你去操作控件更新,而是操作数据。MVVM中的ViewModel就是数据,MVVM中的View就是显示界面。

View绑定的ViewModel需要显式声明,也可以在程序中声明。

<Design.DataContext><!--绑定ViewModel--><vm:MainWindowViewModel/>
</Design.DataContext>

这里的导航菜单,我绑定了一个数组,每个元素的成员如下:

/// <summary>
/// 展示菜单按钮信息
/// </summary>
public class MenuButtonItem
{/// <summary>/// 按钮的图标地址/// </summary>public Bitmap? ImagSource { get; set; }/// <summary>/// 按钮显示的文字/// </summary>public string? ButtonContent { get; set; }/// <summary>/// 按钮点击事件处理/// </summary>public ICommand CommandEvent { get; set; }/// <summary>/// 导航按钮对应的页面/// </summary>public PageViewModelBase PageView { get; set; }public MenuButtonItem(Bitmap? img, string? content, ICommand cmd, PageViewModelBase page){ImagSource = img;ButtonContent = content;CommandEvent = cmd;PageView = page;}
}

包含:

  • 按钮图标
  • 按钮显示的文字
  • 点击事件
  • 导航菜单点击显示的页面

这里的“导航菜单点击显示的页面”是一个ViewModel,代码如下,其余页面绑定的ViewModel都继承于这个类,这样才能写成一个数组的形式,至于如何根据ViewModel显示出对应的View会在下文的“路由”篇介绍。

public abstract class PageViewModelBase : ViewModelBase
{
}

这样就可以使用ItemControl显示内容了,ItemControl绑定一个数组,然后去规定每个Item的显示方式即可,也就是每个Item需要绑定数组元素,内容如下:

<ItemsControl ItemsSource="{Binding MenuButtons}" ><!--模板--><ItemsControl.ItemTemplate><DataTemplate><Button Command="{Binding CommandEvent}" Margin="1,1" Background="Transparent"Width="{Binding $parent[StackPanel].Bounds.Width}"><Grid ColumnDefinitions="Auto,*"><Image Source="{Binding ImageSource}" Width="24" Height="24" Stretch="Fill" /><TextBlock Grid.Column="1" Text="{Binding ButtonContent}" Foreground="White"VerticalAlignment="Center" HorizontalAlignment="Center"/></Grid></Button></DataTemplate></ItemsControl.ItemTemplate>
</ItemsControl>

介绍一下,ItemsControl需要绑定一个集合,这里是ViewModel里的MenuButtons,然后使用模板规定Item的显示方式。Button就是按钮,Command就是绑定了点击事件,Width绑定了父控件StackPanel的Width,这样可以横向填充整个父控件。原始Button没有图标,这里我加了一个Image,显示内容绑定ImageSource,注意,这里的ImageSource必须是已经读取好的Bitmap对象。

关于图像资源,我发现在View里写“avares://AvaloniaDemo/Assets/Img/home.png”,或者直接写“Assets/Img/home.png”就可以读取到,但是在程序里写这个路径就读取不到,必须使用一个工具才能读到,这里我封装了一个图像助手—ImageHelper,具体的看程序吧。

/// <summary>/// 从本地路径读取图像资源/// </summary>/// <param name="resourceUri"></param>/// <returns></returns>public static Bitmap LoadFromResource(Uri resourceUri){return new Bitmap(AssetLoader.Open(resourceUri));}

2.4 路由

这一部分我参考了官方demo程序中关于路由的程序

ViewModel里有一个属性,切换页面的话只需要在按钮的点击事件里把新页面的ViewModel赋值给CurrentPage即可。这里的RaiseAndSetIfChanged就是通知页面更新显示内容,这是MVVM的一部分。

/// <summary>
/// 当前页面
/// </summary>
private PageViewModelBase _CurrentPage;/// <summary>
/// 更换当前页面时提醒页面切换
/// 页面切换的原理使用了反射
/// </summary>
public PageViewModelBase CurrentPage
{get { return _CurrentPage; }private set { this.RaiseAndSetIfChanged(ref _CurrentPage, value); }
}

如何根据ViewModel显示出的View?创建MVVM项目的时候,自带了一个类ViewLocator,咱们看看他的程序

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;}
}

他是把传入的ViewModel名称替换为了View,例如传入“HomePageViewModel”,执行一个转换后就成了“HomePageView”,然后经过反射就找到了对应的界面。所以命名还必须严格按照这个格式才能正常执行。

这里还需要注意两点:

  • 子页面必须使用UserControl

image-20240713115904019

  • 子页面必须绑定对应的ViewModel
<Design.DataContext><!--绑定ViewModel-->
<vm:HomePageViewModel/>

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词