当前位置: 首页 > news >正文

Avalonia 学习笔记01. Images Buttons(图片与按钮) (转载)

转载链接:Avalonia 学习笔记01. Images & Buttons(图片与按钮) - simonoct - 博客园

我对软件的图形化界面很感兴趣,查看了很多框架我最后选定C#的Avalonia作为我第一个学习的框架,不过我发现这个UI框架教程貌似很缺乏。
后面到YouTube上搜,看到一个作者制作了一系列教程,虽然是英文,但是我通过语音转文字+AI翻译学习,感觉还是挺不错的。
视频地址:https://youtu.be/ort9IqKAnL4?si=uTEjZ88osw1BLcyk
资源下载地址:https://github.com/angelsix/youtube/tree/develop/Avalonia BatchProcess

1.1 App.axaml

 
<Application xmlns="https://github.com/avaloniaui"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"x:Class="AvaloniaApplication2.App"RequestedThemeVariant="Default"><!-- "Default" ThemeVariant follows system theme variant. "Dark" or "Light" are other available options. --><Application.Styles><FluentTheme /><StyleInclude Source="Styles/AppDefaultStyles.axaml"></StyleInclude></Application.Styles><Application.Resources><SolidColorBrush x:Key="PrimaryForeground">#CFCFCF</SolidColorBrush><SolidColorBrush x:Key="PrimaryBackground">#14172D</SolidColorBrush><LinearGradientBrush x:Key="PrimaryBackgroundGradient" StartPoint="0%, 0%" EndPoint="100%, 0%"><GradientStop Offset="0" Color="#111214"></GradientStop><GradientStop Offset="1" Color="#151E3E"></GradientStop></LinearGradientBrush><SolidColorBrush x:Key="PrimaryHoverBackground">#333B5A</SolidColorBrush><SolidColorBrush x:Key="PrimaryHoverForeground">White</SolidColorBrush></Application.Resources>
</Application>
  • <Application ...>: 这是根标签,代表你的整个应用程序。

    • xmlns="...": 这些是“命名空间”,可以理解为代码的“地址簿”。它告诉编译器 <Button><Grid>这些标签应该去哪里找它们的定义。初学时不用太关心,知道是必须的就行。
    • RequestedThemeVariant="Default": 设置应用的主题。Default 会跟随你的操作系统是亮色模式还是暗色模式。你也可以强制设为 Dark 或 Light。
  • <Application.Styles>应用的“样式规则手册”。这里面定义了整个应用的外观规则。

    • <FluentTheme />: 引入 Avalonia 官方提供的 Fluent UI 主题。它给了所有控件(按钮、文本框等)一个现代化的、符合 Windows 11 风格的默认外观。
    • <StyleInclude Source="Styles/AppDefaultStyles.axaml" />包含我们自己的样式文件。这行代码告诉“大管家”:“除了官方的 Fluent 主题,再把我们自己写的那个 AppDefaultStyles.axaml 文件里的样式规则也加载进来。” Source 就是文件的路径。使用自定义样式文件可以统一覆盖控件的默认样式,例如直接使用<Button>创建的按钮颜色、鼠标悬停颜色等等,如果一个个button指定颜色不仅混乱,如果遇到修改主题也会变得血雨腥风。
  • <Application.Resources>应用的“公共资源仓库”。这里存放着可以在整个应用中反复使用的“材料”,比如颜色、画刷、图标等。这样做的好处是,如果要改一个颜色,只需要改这里一处,所有用到它的地方都会自动更新。例如AppDefaultStyles.axaml里面就引用了默认的背景颜色、前景颜色,想要变更直接修改颜色即可。

    • <SolidColorBrush x:Key="PrimaryForeground">#CFCFCF</SolidColorBrush>:

      • SolidColorBrush: 定义一个纯色画刷。你可以把它想象成一支只能画一种颜色的油漆刷。
      • x:Key="PrimaryForeground": 给这支油漆刷贴上一个标签(唯一的钥匙),名字叫 PrimaryForeground。之后我们就可以通过这个名字来使用它。
      • #CFCFCF: 这是颜色的十六进制代码。
    • <LinearGradientBrush x:Key="PrimaryBackgroundGradient" ...>: 定义一个线性渐变画刷

      • StartPoint="0%, 0%": 渐变从左上角开始。
      • EndPoint="100%, 0%": 渐变到右上角结束。所以这是一个从左到右的水平渐变
      • <GradientStop Offset="0" Color="..." />: 在渐变轴的起点 (0%) 放置这个颜色。
      • <GradientStop Offset="1" Color="..." />: 在渐变轴的终点 (100%) 放置这个颜色。

 

     假设StartPoint="0%, 0%",EndPoint="100%, 100%",那么渐变轴就是右下角方向了。(0%, 0%)  <-- 起点 (StartPoint)+-------------------------+ (100%, 0%)| \                       ||   \  <-- 渐变轴 (Gradient Axis)|     \                   ||       \                 |+-------------------------+(0%, 100%)           (100%, 100%) <-- 终点 (EndPoint)

 

1.2 Styles/AppDefaultStyles.axaml

新建一个名为Styles的文件夹,然后模板文件可以用Rider新建的时候选择Avalonia Styles,命名为AppDefaultStyles.axaml即可。

这个文件专门用来写我们自定义的样式规则,让应用看起来更个性化。

<Styles xmlns="https://github.com/avaloniaui"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"><Design.PreviewWith><Border Padding="20" Background="{DynamicResource PrimaryBackgroundGradient}" Width="200"><!-- Add Controls for Previewer Here --><Button Foreground="White" Content="Hello World"></Button></Border></Design.PreviewWith><!-- Add Styles Here --><Style Selector="Button"><Setter Property="FontSize" Value="20"></Setter><Setter Property="Foreground" Value="{DynamicResource PrimaryForeground}"></Setter><Setter Property="Background" Value="{DynamicResource PrimaryBackground}"></Setter></Style><Style Selector="Button:pointerover /template/ ContentPresenter"><Setter Property="Foreground" Value="{DynamicResource PrimaryHoverForeground}"></Setter><Setter Property="Background" Value="{DynamicResource PrimaryHoverBackground}"></Setter></Style>
</Styles>
  • <Styles ...>: 这是一个专门存放样式规则的容器。

  • <Design.PreviewWith>“设计师预览区”。这部分代码非常特别,它只在 IDE 的预览窗口里显示,不会被编译到最终的应用里。它的作用是给你提供一个“画板”,让你在设计样式的时候能立刻看到效果,不然就只能靠重新编译或者脑子想象。

  • <Style Selector="Button">定义一条样式规则

    • Selector="Button": 这个是“选择器”,意思是“这条规则将应用到我项目里所有的<Button>控件上”。
    • <Setter Property="FontSize" Value="20" />:
      • Setter: “设置器”,表示要在这里设置一个属性。
      • Property="FontSize": 要设置的属性是“字体大小”。
      • Value="20": 把字体大小的设为 20。
    • <Setter Property="Foreground" Value="{DynamicResource PrimaryForeground}" />: 把文字颜色(Foreground)设置为我们之前在 App.axaml 里定义的、名叫 PrimaryForeground 的那个颜色资源。{DynamicResource ...} 的意思就是“去公共仓库按名字找资源”。
  • <Style Selector="Button:pointerover /template/ ContentPresenter">定义一条更特殊的规则

    • Selector="Button:pointerover": 这个选择器更具体,它说:“这条规则只在鼠标指针悬停在按钮上时才生效”。:pointerover 就是“鼠标悬停”这个特殊状态。
    • /template/ ContentPresenter: 这是个固定写法。它的意思是,为了可靠地改变按钮在悬停时的背景和前景,我们需要更深入地指定到按钮内部一个叫 ContentPresenter 的部件。
    • 里面的两个<Setter>就定义了当鼠标悬停时,按钮的文字颜色和背景色应该变成我们定义的“Hover”颜色。

1.3 MainWindow.axaml

这是用户能看到的、实际的主窗口。它负责把各种控件(按钮、图片等)组合、摆放起来,形成最终的界面。

<Window 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"mc:Ignorable="d" d:DesignWidth="1024" d:DesignHeight="600"Width="1024" Height="600"x:Class="AvaloniaApplication2.MainWindow"Title="AvaloniaApplication2"><Grid Background="{DynamicResource PrimaryBackground}" ColumnDefinitions="Auto, *"><Border Padding="20" Background="{DynamicResource PrimaryBackgroundGradient}"><Grid RowDefinitions="*, Auto"><StackPanel Spacing="12"><Image Source="{SvgImage /Assets/Images/logo.svg}" Width="200"></Image><Button Content="Home" HorizontalAlignment="Stretch"></Button><Button Content="Process" HorizontalAlignment="Stretch"></Button><Button Content="Actions" HorizontalAlignment="Stretch"></Button><Button Content="Macros" HorizontalAlignment="Stretch"></Button><Button Content="Reporter" HorizontalAlignment="Stretch"></Button><Button Content="History" HorizontalAlignment="Stretch"></Button></StackPanel><Button Grid.Row="1" Content="Setting"></Button></Grid></Border></Grid></Window>
  • <Window ...>窗口。这是所有内容的根容器。
    • d:DesignWidth/Height仅在设计预览时的窗口宽高,方便你设计。
    • Width/Height程序真正运行时的窗口宽高。
    • Title: 显示在窗口左上角的标题。
  • <Grid ...>网格。这是布局控件,就像一个看不见的 Excel 表格。
    • Background="{...}": 把窗口的背景设置为我们定义的 PrimaryBackground 颜色。
    • ColumnDefinitions="Auto, *"定义网格的列。这行代码把网格分成了两列:
      • Auto: 第一列的宽度由其内部最宽的内容自动决定
      • *: 第二列将占据所有剩余的可用空间。这是创建“侧边栏 + 主内容区”布局的经典手法。
  • <Border ...>边框容器。它像一个可以设置背景、边框和内边距的盒子。这里它被放在了 Grid 的第一列(Auto 列),用来创建侧边栏。
    • Padding="20": 在这个盒子的四边都留出 20 个单位的内部空白,让内容不会紧贴着边缘。
    • Background="{...}": 把这个侧边栏的背景设置为我们定义的那个渐变色画刷
  • <Grid RowDefinitions="*, Auto">在侧边栏内部又放了一个网格。这个网格用来做垂直布局。
    • RowDefinitions="*, Auto": 把这个内部网格分成了两行:
      • *: 第一行占据所有剩余的垂直空间
      • Auto: 第二行的高度由其内容(设置按钮)自动决定
      • 效果:这会把“设置”按钮“钉”在侧边栏的底部,而上面的部分则会填满剩余空间。
  • <StackPanel Spacing="12">堆叠面板。它是一个简单的布局控件,会把里面的东西一个接一个地堆起来(默认是垂直方向)。
    • Spacing="12": 在每个被堆起来的控件之间,增加 12 个单位的间距。类似于word的行间距。
    • 这个 StackPanel 被放在了内部 Grid 的第一行 (* 行)。
  • <Image ...>图片
    • Source="{SvgImage /Assets/Images/logo.svg}": 设置图片的来源。{SvgImage ...} 是用来加载 SVG 格式矢量图的特殊语法,路径是相对于项目根目录的。注意在Rider里面编辑图片属性,将Bulid Action修改为:AvaloniaResource,不然在构建程序的时候这些资源是不会构建的。
    • Width="200": 设置图片显示的宽度为 200。
    • 注意需要安装一个名为Svg.Controls.Skia.Avalonia的包,教程展示用的是过时版本。
  • <Button ...>按钮
    • Content="Home": 按钮上显示的文字。
    • HorizontalAlignment="Stretch"水平对齐方式。Stretch 意味着让按钮的宽度拉伸,以填满其父容器(StackPanel)分配给它的所有水平空间。
  • <Button Grid.Row="1" Content="Setting" />放在底部的设置按钮
    • Grid.Row="1": 这是一个附加属性。它是在告诉父级的<Grid RowDefinitions="*, Auto">:“请把我这个按钮放在你的第二行(索引从0开始,所以1是第二行)!”,这是实现Setting图标“钉”在底部的关键。
    • 父级的<Grid RowDefinitions="*, Auto">:第一行 (Row="0")** 的高度是 *。意思是:“请占据所有可用的、剩余的垂直空间”,第二行 (Row="1") 的高度是 Auto。意思是:“我的高度刚刚好能包住我的内容就行”。Row="1"就是Auto部分,实现setting在侧边栏的底部。
    • setting会在左侧的原因貌似有些复杂,根据文档所说:HorizontalAlignment和VerticalAlignment默认值都是Stretch,也就是拉伸。但是这里表现却是和显式指定Left一致。一个可能的解释是:因为父 Grid 列是 Auto。Auto 列的宽度由子控件的“理想尺寸”决定。虽然按钮的 HorizontalAlignment 默认是 Stretch,但它必须先报告一个尺寸给 Auto 列。这个尺寸就是它包裹其内容(HorizontalContentAlignment 为 Left)所需的最小尺寸。因此,Grid 列和按钮本身都收缩了,Stretch 没有机会发挥作用。
    • 显式指定 HorizontalAlignment="Stretch"时,默认保守策略会被覆盖,找一个最大且具体(非无限宽)的宽度,然后拉伸。这里因为<Image ... Width=200>,所以最大宽度就是200。如果想让图标也居中,则需要额外指定HorizontalContentAlignment="Center"

1.4 <Grid>

Grid 的核心在于先定义网格,再放置内容

1.4.1 定义行和列

用 <Grid.ColumnDefinitions><Grid.RowDefinitions>来定义网格的结构。每一列或每一行的大小有三种定义方式:

  1. Auto (按需分配):列宽或行高由其内部最宽/最高的内容决定。它会“收缩/撑开”以正好包裹住内容。
<Grid ColumnDefinitions="Auto, *"><Button Grid.Column="0">短内容</Button><Button Grid.Column="1">这里是很长很长的内容</Button>
</Grid>
|-- 由“短内容”决定 --|---------- 占据所有剩余空间 -----------|
|  [ 短内容 ]       |  [ 这里是很长很长的内容 ]              |
|      (Auto)      |                  (*)               |
  1. *** (星号/比例分配):这是最强大的方式。它会贪婪地抢占所有“剩余”的空间**。如果多个列/行都是 *,它们会按比例瓜分。
  • *, *:两个都分 1 份,所以是 1:1,即对半分。
  • *, 2*:一个分 1 份,一个分 2 份,总共 3 份,所以是 1:2 的比例。

假设宽度是900px

|----------- 300px (1份) -----------|----------------- 600px (2份) -----------------|
|                                   |                                              |
|                (*)                |                     (2*)                     |
  1. 固定值 (Fixed Value):直接指定一个固定的数字,单位是设备无关像素。
<Grid ColumnDefinitions="100, *"><Button Grid.Column="0">固定100宽</Button><Button Grid.Column="1">剩余所有</Button>
</Grid>
|---- 100px ----|------------------ 占据所有剩余空间 ------------------|
| [ 固定100宽 ]  |  [ 剩余所有 ]                                       |
|   (Fixed)     |                         (*)                        |

1.4.2 放置控件

使用 Grid.Row 和 Grid.Column 附加属性,告诉每个控件应该去哪个“房间”(单元格)。索引从 0 开始。

<!-- 一个 2x2 的网格 -->
<Grid ColumnDefinitions="*,*" RowDefinitions="*,*"><!-- 左上角 (0,0) --><Button Grid.Row="0" Grid.Column="0" Content="A"/><!-- 右上角 (0,1) --><Button Grid.Row="0" Grid.Column="1" Content="B"/><!-- 左下角 (1,0) --><Button Grid.Row="1" Grid.Column="0" Content="C"/><!-- 右下角 (1,1) --><Button Grid.Row="1" Grid.Column="1" Content="D"/>
</Grid>
      Column 0 (*)      Column 1 (*)+-----------------+-----------------+|                 |                 |  Row 0 (*)|    [   A   ]    |    [   B   ]    ||     (0,0)       |     (0,1)       ||                 |                 |+-----------------+-----------------+|                 |                 |  Row 1 (*)|    [   C   ]    |    [   D   ]    ||     (1,0)       |     (1,1)       ||                 |                 |+-----------------+-----------------+

1.4.3 Grid 可以包含StackPanel吗?

正如上方教程展示的代码,Grid可以包含StackPanel,后续视频教程可能会深入这里我就简单找一例:

<Grid ColumnDefinitions="Auto, *"><!-- Grid的第0列: 放置一个StackPanel来管理一堆按钮 --><StackPanel Grid.Column="0" Margin="10" Spacing="8"><Button>首页</Button><Button>产品</Button><Button>设置</Button><Button>关于</Button></StackPanel><!-- Grid的第1列: 放置主内容 --><Border Grid.Column="1" Background="LightGray"><TextBlock VerticalAlignment="Center" HorizontalAlignment="Center">主内容区域</TextBlock></Border></Grid>
<---------------------------------- Grid (整体框架) ----------------------------------->
+---------------------------------+---------------------------------------------------+
| <-- StackPanel (在第0列) ------> |                                                   |
|                                 |                                                   |
|   +-------------------------+   |                                                   |
|   |       [ 首页 ]           |   |                                                   |
|   +-------------------------+   |                                                   |
|   |       [ 产品 ]           |   |                                                   |
|   +-------------------------+   |                   主内容区域                        |
|   |       [ 设置 ]           |   |                     (第1列)                       |
|   +-------------------------+   |                                                   |
|   |       [ 关于 ]           |   |                                                  |
|   +-------------------------+   |                                                   |
|                                 |                                                   |
+---------------------------------+---------------------------------------------------+
| <------- Col 0 (Auto) --------> | <-------------------- Col 1 (*) -----------------> |

1.5 <StackPanel>

StackPanel 的核心是按顺序线性排列。它只有两个关键属性你需要关心。

1.5.1 Orientation (方向)

  • Vertical (默认值): 从上到下堆叠。
  • Horizontal: 从左到右排列。
<!-- 垂直方向 (默认) -->
<StackPanel><Button>A</Button><Button>B</Button><Button>C</Button>
</StackPanel>
+-----------+
| [   A   ] |
+-----------+
| [   B   ] |
+-----------+
| [   C   ] |
+-----------+
<!-- 水平方向 -->
<StackPanel Orientation="Horizontal"><Button>A</Button><Button>B</Button><Button>C</Button>
</StackPanel>
+---------+---------+---------+
| [  A  ] | [  B  ] | [  C  ] |
+---------+---------+---------+

1.5.2 Spacing (间距)

在每个子控件之间添加固定的空白。

<StackPanel Spacing="10"><Button>A</Button><Button>B</Button>
</StackPanel>
+-----------+
| [   A   ] |
+-----------+
|-- 10px空隙--|  <-- Spacing
+-----------+
| [   B   ] |
+-----------+

1.5.3 StackPanel 可以包含 Grid 吗?

可以

可能的场景:当你需要构建一个列表,而列表中的每一项本身又是一个复杂的布局时。例如,一个显示用户信息的垂直列表。

<StackPanel Spacing="10"><!-- 第一张用户卡片 (一个 Grid) --><Grid ColumnDefinitions="Auto, *"><Image Grid.Column="0" Source="avatar1.png" Width="50"/><StackPanel Grid.Column="1" Margin="10,0,0,0"><TextBlock>张三</TextBlock><TextBlock>软件工程师</TextBlock></StackPanel></Grid><!-- 第二张用户卡片 (另一个 Grid) --><Grid ColumnDefinitions="Auto, *"><Image Grid.Column="0" Source="avatar2.png" Width="50"/><StackPanel Grid.Column="1" Margin="10,0,0,0"><TextBlock>李四</TextBlock><TextBlock>UI 设计师</TextBlock></StackPanel></Grid></StackPanel>
+---------------------------------------------+  <-- StackPanel 开始
|                                             |
| +-----------------------------------------+ |  <-- 第一个 Grid 开始
| |          |                              | |
| | [头像1]   |  张三                         | |
| |  (Auto)  |  软件工程师                    | |
| |          |         (*)                  | |
| +-----------------------------------------+ |  <-- 第一个 Grid 结束
|                                             |
|----------------- 10px 间距 -----------------|
|                                             |
| +-----------------------------------------+ |  <-- 第二个 Grid 开始
| |          |                              | |
| | [头像2]  |  李四                         | |
| |  (Auto)  |  UI 设计师                    | |
| |          |         (*)                  | |
| +-----------------------------------------+ |  <-- 第二个 Grid 结束
|                                             |
+---------------------------------------------+  <-- StackPanel 结束

 

http://www.agseo.cn/news/106/

相关文章:

  • 【触想智能】工控一体机和PLC一体机的区别你知道吗?
  • JDK 24.0.1 下载安装教程与环境配置教程(Windows10/11超详细图文安装步骤)
  • XeLaTeX 介绍
  • PTA
  • 学习笔记-安全概述
  • Adobe Animate CC2018安装包下载与安装教程
  • AE苹果手机iPhone 17展示动画片头模板 App Promo Phone 17 Pro
  • 完整教程:以数据与自动化驱动实验室变革:智能化管理整体规划
  • Windows11新系统激活设置PIN码步骤转圈
  • 82、制作座位表
  • 工业硅2511
  • 人工智能时代的合规性:为什么强大的 CI/CD 基础很重要
  • 如何优雅地清理Hugging Face缓存到本地的模型文件(2025最新版)
  • Linux 进程上下文切换详解
  • 第十天 C#学习事件 021
  • 事半功倍是蠢蛋52 使用docker-compose.override.yml
  • Elasticsearch
  • MySQL单表查询DQL
  • PyQt5 之QMenu菜单栏
  • [TJOI2015] 概率论 题解
  • Linux进程与线程
  • 事半功倍是蠢蛋51 大上黑白屏反色
  • Linux 启动耗时优化 1s 内启动(RK3588 平台)
  • 周总结报告5
  • 使用模拟库进行测试的意义是什么?
  • MyEMS:开源领域的能源管理创新解决方案
  • 【Containerd交互命令】ctr、crictl常用基本命令
  • DAG Matters! GFlowNets Enhanced Explainer For Graph Neural Networks | |
  • abap字符串操作
  • [完结16章]COZE AI 智能体开发体系课(从入门到高级)零基础零代码